Пример 4.2.1 является примером программы, демонстрирующей порядок использования интерфейса
больших объектов
в libpq can be used. Отдельные части программы закомментированы, но сохранены в исходном коде для удобства изучения. Данная программа также находится в файле
src/test/examples/testlo.c в составе исходных кодов дистрибутива.
Пример 4.2.1. Большие объекты в libpq Пример программы
/*----------------------------------------------------------------- * * testlo.c * тестирование работы с большими объектами через libpq * * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * src/test/examples/testlo.c * *----------------------------------------------------------------- */ #include#include #include #include #include #include #include "libpq-fe.h" #include "libpq/libpq-fs.h" #define BUFSIZE 1024 /* * importFile — * импорт файла «in_filename» в базу данных в качестве большого объекта «lobjOid» * */ static Oid importFile(PGconn *conn, char *filename) { Oid lobjId; int lobj_fd; char buf[BUFSIZE]; int nbytes, tmp; int fd; /* * открытие файла для чтения */ fd = open(filename, O_RDONLY, 0666); if (fd < 0) { /* ошибка */ fprintf(stderr, "не удалось открыть unix-файл \"%s\"\n", filename); } /* * создание большого объекта */ lobjId = lo_creat(conn, INV_READ | INV_WRITE); if (lobjId == 0) fprintf(stderr, "cannot create large object"); lobj_fd = lo_open(conn, lobjId, INV_WRITE); /* * чтение из файла Unix и запись в инвертированный файл */ while ((nbytes = read(fd, buf, BUFSIZE)) > 0) { tmp = lo_write(conn, lobj_fd, buf, nbytes); if (tmp < nbytes) fprintf(stderr, "error while reading \"%s\"", filename); } close(fd); lo_close(conn, lobj_fd); return lobjId; } static void pickout(PGconn *conn, Oid lobjId, int start, int len) { int lobj_fd; char *buf; int nbytes; int nread; lobj_fd = lo_open(conn, lobjId, INV_READ); if (lobj_fd < 0) fprintf(stderr, "cannot open large object %u", lobjId); lo_lseek(conn, lobj_fd, start, SEEK_SET); buf = malloc(len + 1); nread = 0; while (len - nread > 0) { nbytes = lo_read(conn, lobj_fd, buf, len - nread); buf[nbytes] = '\0'; fprintf(stderr, ">>> %s", buf); nread += nbytes; if (nbytes <= 0) break; /* данных больше нет? */ } free(buf); fprintf(stderr, "\n"); lo_close(conn, lobj_fd); } static void overwrite(PGconn *conn, Oid lobjId, int start, int len) { int lobj_fd; char *buf; int nbytes; int nwritten; int i; lobj_fd = lo_open(conn, lobjId, INV_WRITE); if (lobj_fd < 0) fprintf(stderr, "cannot open large object %u", lobjId); lo_lseek(conn, lobj_fd, start, SEEK_SET); buf = malloc(len + 1); for (i = 0; i < len; i++) buf[i] = 'X'; buf[i] = '\0'; nwritten = 0; while (len - nwritten > 0) { nbytes = lo_write(conn, lobj_fd, buf + nwritten, len - nwritten); nwritten += nbytes; if (nbytes <= 0) { fprintf(stderr, "\nОШИБКА ЗАПИСИ!\n"); break; } } free(buf); fprintf(stderr, "\n"); lo_close(conn, lobj_fd); } /* * exportFile - * экспорт большого объекта «lobjOid» в файл «out_filename» * */ static void exportFile(PGconn *conn, Oid lobjId, char *filename) { int lobj_fd; char buf[BUFSIZE]; int nbytes, tmp; int fd; /* * открытие большого объекта */ lobj_fd = lo_open(conn, lobjId, INV_READ); if (lobj_fd < 0) fprintf(stderr, "не удалось открыть большой объект %u", lobjId); /* * открытие файла для записи */ fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666); if (fd < 0) { /* ошибка */ fprintf(stderr, "не удалось открыть файл Unix \"%s\"", filename); } /* * чтение из инвертированного файла и запись в файл Unix */ while ((nbytes = lo_read(conn, lobj_fd, buf, BUFSIZE)) > 0) { tmp = write(fd, buf, nbytes); if (tmp < nbytes) { fprintf(stderr, "ошибка при записи \"%s\"", filename); } } lo_close(conn, lobj_fd); close(fd); } static void exit_nicely(PGconn *conn) { PQfinish(conn); exit(1); } int main(int argc, char **argv) { char *in_filename, *out_filename; char *database; Oid lobjOid; PGconn *conn; PGresult *res; if (argc != 4) { fprintf(stderr, "Использование: %s имя_базы_данных входной_файл выходной_файл\n", argv[0]); exit(1); } database = argv[1]; in_filename = argv[2]; out_filename = argv[3]; /* * установка соединения */ conn = PQsetdb(NULL, NULL, NULL, NULL, database); /* проверка успешности установления соединения с серверной частью */ if (PQstatus(conn) != CONNECTION_OK) { fprintf(stderr, "%s", PQerrorMessage(conn)); exit_nicely(conn); } /* Установка безопасного пути поиска (search_path) для защиты от злоумышленников. */ res = PQexec(conn, "SELECT pg_catalog.set_config('search_path', '', false)"); if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr, "Ошибка выполнения SET: %s", PQerrorMessage(conn)); PQclear(res); exit_nicely(conn); } PQclear(res); res = PQexec(conn, "begin"); PQclear(res); printf("импорт файла \"%s\" ...\n", in_filename); /* lobjOid = importFile(conn, in_filename); */ lobjOid = lo_import(conn, in_filename); if (lobjOid == 0) fprintf(stderr, "%s\n", PQerrorMessage(conn)); else { printf("\tкак большой объект %u.\n", lobjOid); printf("извлечение байтов 1000–2000 из большого объекта\n"); pickout(conn, lobjOid, 1000, 1000); printf("перезапись байтов 1000–2000 большого объекта символами X\n"); overwrite(conn, lobjOid, 1000, 1000); printf("экспорт большого объекта в файл \"%s\" ...\n", out_filename); /* exportFile(conn, lobjOid, out_filename); */ if (lo_export(conn, lobjOid, out_filename) < 0) fprintf(stderr, "%s\n", PQerrorMessage(conn)); } res = PQexec(conn, "end"); PQclear(res); PQfinish(conn); return 0; }