Ejemplo n.º 1
0
	function get_table_copy($table, $seperator=NULL, $null_value=NULL)
	{
		// uses pg_copy_to to return an array of an entire table
		// good for use of 'export table out'
		switch (func_num_args()) {
		case 1:
			return pg_copy_to($this->db, $table);
			break;
		case 2:
			return pg_copy_to($this->db, $table, $seperator);
			break;
		case 3:
			return ($seperator != NULL ?pg_copy_to($this->db, $table, $seperator, $null_value) : pg_copy_to($this->db, $table, NULL, $null_value));
			break;
		}

	}
Ejemplo n.º 2
0
 /**
  * Считает почасовую статистику.
  * Берет данные из stat_log до последнего часа и группирует их в промежутках по одному часу, uid смотрящего и uid кого смотрели.
  * Т.е. любое кол-во просмотров кем-либо (guest_id) в течении часа кого-либо (user_id) считается одним просмотром.
  * Сгруппированные данные сохраняются в stat_hourly, а полный дамп просмотров кладется в файл в директории $this->arc
  * @return   string   сообщение об ошибке или 0, если все прошло успешно
  */
 function Step1()
 {
     // Отправляем данные из stat_log в stat_hourly. Ежечасно.
     // Архивный лог ($arc_name) не удаляем. Пусть будут дубли, не страшно. Потом при использовании, нужно будет их очистить и все.
     // Еще заводим лог ошибок.
     $DB = $this->_sDB;
     $this->log('stat_collector::Step1(). Экспорт данных из stat_log в stat_hourly.', self::LT_SUBHEADER);
     $time = $this->get_time();
     $curH = date('Y-m-d H', $time) . ':00:00';
     $curTH = strtotime($curH);
     // 1. Убиваем индекс "ix stat_log_t/_time" для облегчения последующей переправки данных в stat_log_t.
     // 2. Перенаправляем инсерт на stat_log_t.
     // 3. Переносим все данные в stat_log_t.
     // 4. TRUNCATE stat_log.
     // 5. Возвращаем инсерты на stat_log.
     // 6. Создаем индекс "ix stat_log_t/_time" снова, чтобы использовать его в селектах.
     // 7. Обрабатываем по одному часу stat_log_t.
     // 8. В конце делаем VACUUM FULL stat_log_t.
     // Таким образом вся обработка будет осуществляться на таблице stat_log_t. В начале каждого вызова данной функции,
     // stat_log_t будет содержать данные за неполный предыдущий час (_time >= $curH в предыдущем вызове), которые будут дополняться
     // новыми данными, накопившимися в stat_log .
     $this->log('Удаляем индекс "ix stat_log_t/_time".', self::LT_NOTICE);
     $sql = 'DROP INDEX IF EXISTS "ix stat_log_t/_time"';
     if (!$this->_sDB->squery($sql)) {
         $this->log('Ошибка. ' . $this->_sDB->error, self::LT_WARNING);
     }
     $this->log('Перенаправляем инсерты на stat_log_t.', self::LT_NOTICE);
     if (!$this->_setLogTable('stat_log_t')) {
         return $this->log('Ошибка. ', self::LT_ERROR);
     }
     $this->log('Ок.', self::LT_NOTICE);
     $this->log('Ждем 3 секунды для завершения старых транзакций...', self::LT_NOTICE);
     sleep(3);
     $truncateErr = NULL;
     $this->log('Переносим все данные из stat_log в stat_log_t, TRUNCATE ONLY stat_log.', self::LT_NOTICE);
     $sql = 'INSERT INTO stat_log_t SELECT * FROM ONLY stat_log';
     if (!$DB->squery($sql)) {
         $truncateErr = $this->log('Ошибка. ' . $DB->error, self::LT_ERROR);
     } else {
         $sql = 'TRUNCATE ONLY stat_log';
         if (!$DB->squery($sql)) {
             $truncateErr = $this->log('Ошибка. ' . $DB->error, self::LT_ERROR);
         }
     }
     $this->log('Возвращаем инсерты на stat_log.', self::LT_NOTICE);
     if (!$this->_setLogTable('stat_log')) {
         return $this->log('Ошибка. ', self::LT_ERROR);
     }
     if ($truncateErr) {
         return $truncateErr;
     }
     $this->log('Восстанавливаем индекс "ix stat_log_t/_time".', self::LT_NOTICE);
     $sql = 'CREATE INDEX CONCURRENTLY "ix stat_log_t/_time" ON stat_log_t USING btree (_time)';
     if (!$DB->squery($sql)) {
         $this->log('Ошибка. ' . $DB->error, self::LT_WARNING);
     }
     $lT = $DB->val("SELECT _time FROM stat_log_t ORDER BY _time LIMIT 1");
     if ($DB->error) {
         return $this->log('Ошибка чтения stat_log_t. ' . $DB->error, self::LT_ERROR);
     }
     if (!$lT) {
         return $this->log('Данных нет.', self::LT_NOTICE);
     }
     $tH = strtotime(date('Y-m-d H', strtotime($lT)) . ':00:00');
     if ($tH < $curTH) {
         $tH += 3600;
     }
     // Обрабатываем по одному часу.
     for ($tH; $tH <= $curTH; $tH += 3600) {
         $H = date('Y-m-d H', $tH) . ':00:00';
         // в конец $arc_name добавлен суффикс H, т.к. в разное время из-за всяких сбоев может обрабатываться один и тот же час,
         // это приводило к затиранию предыдущего архива.
         $arc_name = $this->arc_dir . '/' . date('YmdH', $tH) . '-' . date('H') . '.log';
         $this->log("Обработка данных: FROM stat_log_t WHERE _time < '{$H}'.", self::LT_NOTICE);
         // (а) Проверяем, есть ли данные в stat_log_t, которые можно экспортировать.
         $sql = "SELECT 1 FROM stat_log_t WHERE _time < ? LIMIT 1";
         if (!($res = $DB->query($sql, $H))) {
             return $this->log('Ошибка чтения stat_log_t. ' . $DB->error, self::LT_ERROR);
         }
         if (!pg_num_rows($res)) {
             $this->log("Данных нет.", self::LT_NOTICE);
             continue;
         }
         // (б) Берем данные из stat_log_t за все "полные часы" (все, кроме текущего часа) и выбрасываем их во временную таблицу и в хранилище логов.
         //     Данные выбрасываются в чистом виде, без преобразований и упаковываются (пока не упаковываются).
         //     В случае ошибки прекращаем операцию.
         if (!$DB->start()) {
             return $this->log('Не удалось открыть транзакцию. ' . $DB->error, self::LT_ERROR);
         }
         $sql = "SELECT * INTO TEMPORARY TABLE ___tmp_arc FROM stat_log_t WHERE _time < ?";
         if (!($res = $DB->query($sql, $H))) {
             $e = $DB->error;
             $DB->rollback();
             return $this->log('Ошибка инсерта в ___tmp_arc. ' . $e, self::LT_ERROR);
         }
         $all_data = pg_copy_to($DB->connect(), '___tmp_arc');
         if (!file_put_contents($arc_name, $all_data)) {
             $this->log("Лог {$arc_name} не записался.", self::LT_WARNING);
         }
         unset($all_data);
         // Пригодится для отката в случае конфликта ключей.
         if (!$DB->query('SAVEPOINT arc_created')) {
             $e = $DB->error;
             $DB->rollback();
             return $this->log('Не удалось создать SAVEPOINT. ' . $e, self::LT_ERROR);
         }
         // (в) Берем данные из stat_log_t за тот же период, что и в (б), но группируем их специальным образом, так, чтобы не было ничего "лишнего".
         // (г) Если ошибка возникла в связи с конфликтом ключей (тут конкретная такая проверка,
         //     то есть, теперь мы не гурьбой пытаемся запихнуть данные, а через временную таблицу пробуем загрузить только
         //     "не дубликаты"), то удаляем файл. Иначе удаляем файл и прекращаем операцию.
         //     Каждый час занимаемся только конкретными данными, только одним .tmp файлом. Если он не проходит в
         //     stat_hourly по причине сбоя какого-нибудь, то прекращаем операцию. Так будет гарантия непрерывности данных,
         //     которая необходима для наращивания счетчиков (итоговых) в stat_summary.
         $grp_data_sql = "(\n         SELECT user_id,\n                guest_id,\n                CASE WHEN guest_id = 0 THEN guest_ip ELSE '' END as guest_ip,\n                by_e,\n                MAX(_time) as _time,\n                MAX((referer_id=" . self::REFID_BLOGS . ")::int)::bool as from_b,\n                MAX((referer_id=" . self::REFID_CATALOG . ")::int)::bool as from_c,\n                MAX((referer_id=" . self::REFID_PAIDSEATINGS . ")::int)::bool as from_p,\n\t\t\t\tMAX((referer_id=" . self::REFID_PAYPLACE . ")::int)::bool as from_t,\n\t\t\t\tMAX((referer_id=" . self::REFID_FRL_OFFERS . ")::int)::bool as from_o,\n\t\t\t\tMAX((referer_id=" . self::REFID_SEARCH . ")::int)::bool as from_s\n           FROM ___tmp_arc\n          GROUP BY \n                user_id,\n                guest_id,\n                CASE WHEN guest_id = 0 THEN guest_ip ELSE '' END,\n                by_e,\n                DATE_TRUNC('hour', _time)\n       )";
         $sql = "INSERT INTO stat_hourly (user_id, guest_id, guest_ip, by_e, _time, from_b, from_c, from_p, from_t, from_o, from_s) SELECT * FROM {$grp_data_sql} t";
         if (!($res = $DB->squery($sql))) {
             $e = $DB->error;
             $DB->squery("ROLLBACK TO SAVEPOINT arc_created");
             // откатываемся к "после создания вр. таблицы"
             $this->log('Ошибка при инсерте в stat_hourly. Возможно конфликт ключей, откатываемся, пытаемся обойти. ' . $e, self::LT_WARNING);
             $sql = "INSERT INTO stat_hourly (user_id, guest_id, guest_ip, by_e, _time, from_b, from_c, from_p, from_t, from_o, from_s)\n         SELECT t.*\n           FROM {$grp_data_sql} t\n         LEFT JOIN\n           stat_hourly h\n             ON h.user_id  = t.user_id\n            AND h.guest_id = t.guest_id\n            AND h.guest_ip = t.guest_ip\n            AND h._time    = t._time\n            \n-- !!! Нужно AND DATE_TRUNC('hour', h._time) = DATE_TRUNC('hour', t._time)\n-- !!! и индекс переделать (user_id, guest_id, guest_ip, DATE_TRUNC('hour', _time))\n            \n          WHERE h.user_id IS NULL";
             if (!($res = $DB->squery($sql))) {
                 $e = $DB->error;
                 $DB->rollback();
                 // откатываемся по полной.
                 return $this->log('Ошибка не в конфликте ключей. ' . $e, self::LT_ERROR);
             }
         }
         $this->log('Получено ' . pg_affected_rows($res) . ' строк.', self::LT_NOTICE);
         pg_free_result($res);
         // Фиксируем все это дело.
         if (!$DB->commit()) {
             $e = $DB->error;
             $DB->rollback();
             return $this->log('Не удалось зафиксировать транзакцию. ' . $e, self::LT_ERROR);
         }
         $DB->squery('DROP TABLE IF EXISTS ___tmp_arc');
         // (д) Удаляем эспортированные данные из stat_log_t. Они уже не нужны, т.к. они уже есть в stat_hourly.
         //     Если данные не удалились, то в следующий раз сработает проверка на дубликаты в пункте (г), так что все должно
         //     быть окей.
         $DB->start();
         $sql = "DELETE FROM stat_log_t WHERE _time < ?";
         if (!($res = $DB->query($sql, $H)) || !$DB->commit()) {
             $e = $DB->error;
             $DB->rollback();
             $this->log('Ошибка при удалении из stat_log_t. ' . $e, self::LT_WARNING);
         } else {
             pg_free_result($res);
         }
         $this->log('Ок.', self::LT_NOTICE);
     }
     $this->log('Пылесосим stat_log_t.', self::LT_NOTICE);
     if (!$DB->squery('VACUUM FULL stat_log_t')) {
         $this->log('VACUUM FULL stat_log_t не сработал. ' . $DB->error, self::LT_WARNING);
     }
     return 0;
 }
Ejemplo n.º 3
0
<?php

include 'config.inc';
$db = pg_connect($conn_str);
$rows = pg_copy_to($db, $table_name);
pg_query($db, "DELETE FROM {$table_name}");
pg_copy_from($db, $table_name, $rows);
echo "OK";
Ejemplo n.º 4
0
 $i = 0;
 $field_headings = array();
 while ($row = pg_fetch_object($result)) {
     $field_headings[] = $row->column_name;
     switch ($row->column_name) {
         case 'id':
             $pos_id = $i;
             break;
         case 'reporter_id':
             $pos_reporter_id = $i;
             break;
     }
     $i++;
 }
 array_splice($field_headings, $pos_id, 1);
 if ($data = pg_copy_to($db->getHandle(), 'incidents', "\t")) {
     header('Content-Type: application/octet-stream');
     header('Content-Disposition: attachment; filename="My PAT Facebook reports.tsv"');
     header('Pragma: no-cache');
     if (isset($_GET['header'])) {
         print implode("\t", $field_headings) . "\n";
     }
     foreach ($data as $line) {
         $fields = explode("\t", $line);
         if ($user_id == $fields[$pos_reporter_id]) {
             array_splice($fields, $pos_id, 1);
             print implode("\t", $fields);
         }
     }
 }
 exit;