fe-lobj.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:12k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * fe-lobj.c
  4.  *   Front-end large object interface
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/interfaces/libpq/fe-lobj.c,v 1.20 1999/05/10 00:46:26 momjian Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. #include "libpq-fe.h"
  15. #include "libpq-int.h"
  16. #include "postgres.h"
  17. #ifdef WIN32
  18. #include "win32.h"
  19. #include <io.h>
  20. #else
  21. #if !defined(NO_UNISTD_H)
  22. #include <unistd.h>
  23. #endif
  24. #endif
  25. #include <string.h>
  26. #include <fcntl.h>
  27. #include <sys/stat.h>
  28. #include "libpq/libpq-fs.h" /* must come after sys/stat.h */
  29. #define LO_BUFSIZE   1024
  30. static int lo_initialize(PGconn *conn);
  31. /*
  32.  * lo_open
  33.  *   opens an existing large object
  34.  *
  35.  * returns the file descriptor for use in later lo_* calls
  36.  * return -1 upon failure.
  37.  */
  38. int
  39. lo_open(PGconn *conn, Oid lobjId, int mode)
  40. {
  41. int fd;
  42. int result_len;
  43. PQArgBlock argv[2];
  44. PGresult   *res;
  45. argv[0].isint = 1;
  46. argv[0].len = 4;
  47. argv[0].u.integer = lobjId;
  48. argv[1].isint = 1;
  49. argv[1].len = 4;
  50. argv[1].u.integer = mode;
  51. if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
  52. {
  53. if (lo_initialize(conn) < 0)
  54. return -1;
  55. }
  56. res = PQfn(conn, conn->lobjfuncs->fn_lo_open, &fd, &result_len, 1, argv, 2);
  57. if (PQresultStatus(res) == PGRES_COMMAND_OK)
  58. {
  59. PQclear(res);
  60. /* have to do this to reset offset in shared fd cache */
  61. /* but only if fd is valid */
  62. if (fd >= 0 && lo_lseek(conn, fd, 0L, SEEK_SET) < 0)
  63. return -1;
  64. return fd;
  65. }
  66. else
  67. {
  68. PQclear(res);
  69. return -1;
  70. }
  71. }
  72. /*
  73.  * lo_close
  74.  *   closes an existing large object
  75.  *
  76.  * returns 0 upon success
  77.  * returns -1 upon failure.
  78.  */
  79. int
  80. lo_close(PGconn *conn, int fd)
  81. {
  82. PQArgBlock argv[1];
  83. PGresult   *res;
  84. int retval;
  85. int result_len;
  86. if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
  87. {
  88. if (lo_initialize(conn) < 0)
  89. return -1;
  90. }
  91. argv[0].isint = 1;
  92. argv[0].len = 4;
  93. argv[0].u.integer = fd;
  94. res = PQfn(conn, conn->lobjfuncs->fn_lo_close,
  95.    &retval, &result_len, 1, argv, 1);
  96. if (PQresultStatus(res) == PGRES_COMMAND_OK)
  97. {
  98. PQclear(res);
  99. return retval;
  100. }
  101. else
  102. {
  103. PQclear(res);
  104. return -1;
  105. }
  106. }
  107. /*
  108.  * lo_read
  109.  *   read len bytes of the large object into buf
  110.  *
  111.  * returns the length of bytes read.
  112.  * the CALLER must have allocated enough space to hold the result returned
  113.  */
  114. int
  115. lo_read(PGconn *conn, int fd, char *buf, int len)
  116. {
  117. PQArgBlock argv[2];
  118. PGresult   *res;
  119. int result_len;
  120. if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
  121. {
  122. if (lo_initialize(conn) < 0)
  123. return -1;
  124. }
  125. argv[0].isint = 1;
  126. argv[0].len = 4;
  127. argv[0].u.integer = fd;
  128. argv[1].isint = 1;
  129. argv[1].len = 4;
  130. argv[1].u.integer = len;
  131. res = PQfn(conn, conn->lobjfuncs->fn_lo_read,
  132.    (int *) buf, &result_len, 0, argv, 2);
  133. if (PQresultStatus(res) == PGRES_COMMAND_OK)
  134. {
  135. PQclear(res);
  136. return result_len;
  137. }
  138. else
  139. {
  140. PQclear(res);
  141. return -1;
  142. }
  143. }
  144. /*
  145.  * lo_write
  146.  *   write len bytes of buf into the large object fd
  147.  *
  148.  */
  149. int
  150. lo_write(PGconn *conn, int fd, char *buf, int len)
  151. {
  152. PQArgBlock argv[2];
  153. PGresult   *res;
  154. int result_len;
  155. int retval;
  156. if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
  157. {
  158. if (lo_initialize(conn) < 0)
  159. return -1;
  160. }
  161. if (len <= 0)
  162. return 0;
  163. argv[0].isint = 1;
  164. argv[0].len = 4;
  165. argv[0].u.integer = fd;
  166. argv[1].isint = 0;
  167. argv[1].len = len;
  168. argv[1].u.ptr = (int *) buf;
  169. res = PQfn(conn, conn->lobjfuncs->fn_lo_write,
  170.    &retval, &result_len, 1, argv, 2);
  171. if (PQresultStatus(res) == PGRES_COMMAND_OK)
  172. {
  173. PQclear(res);
  174. return retval;
  175. }
  176. else
  177. {
  178. PQclear(res);
  179. return -1;
  180. }
  181. }
  182. /*
  183.  * lo_lseek
  184.  *   change the current read or write location on a large object
  185.  * currently, only L_SET is a legal value for whence
  186.  *
  187.  */
  188. int
  189. lo_lseek(PGconn *conn, int fd, int offset, int whence)
  190. {
  191. PQArgBlock argv[3];
  192. PGresult   *res;
  193. int retval;
  194. int result_len;
  195. if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
  196. {
  197. if (lo_initialize(conn) < 0)
  198. return -1;
  199. }
  200. argv[0].isint = 1;
  201. argv[0].len = 4;
  202. argv[0].u.integer = fd;
  203. argv[1].isint = 1;
  204. argv[1].len = 4;
  205. argv[1].u.integer = offset;
  206. argv[2].isint = 1;
  207. argv[2].len = 4;
  208. argv[2].u.integer = whence;
  209. res = PQfn(conn, conn->lobjfuncs->fn_lo_lseek,
  210.    &retval, &result_len, 1, argv, 3);
  211. if (PQresultStatus(res) == PGRES_COMMAND_OK)
  212. {
  213. PQclear(res);
  214. return retval;
  215. }
  216. else
  217. {
  218. PQclear(res);
  219. return -1;
  220. }
  221. }
  222. /*
  223.  * lo_creat
  224.  *   create a new large object
  225.  * the mode is a bitmask describing different attributes of the new object
  226.  *
  227.  * returns the oid of the large object created or
  228.  * InvalidOid upon failure
  229.  */
  230. Oid
  231. lo_creat(PGconn *conn, int mode)
  232. {
  233. PQArgBlock argv[1];
  234. PGresult   *res;
  235. int retval;
  236. int result_len;
  237. if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
  238. {
  239. if (lo_initialize(conn) < 0)
  240. return -1;
  241. }
  242. argv[0].isint = 1;
  243. argv[0].len = 4;
  244. argv[0].u.integer = mode;
  245. res = PQfn(conn, conn->lobjfuncs->fn_lo_creat,
  246.    &retval, &result_len, 1, argv, 1);
  247. if (PQresultStatus(res) == PGRES_COMMAND_OK)
  248. {
  249. PQclear(res);
  250. return (Oid) retval;
  251. }
  252. else
  253. {
  254. PQclear(res);
  255. return InvalidOid;
  256. }
  257. }
  258. /*
  259.  * lo_tell
  260.  *   returns the current seek location of the large object
  261.  *
  262.  */
  263. int
  264. lo_tell(PGconn *conn, int fd)
  265. {
  266. int retval;
  267. PQArgBlock argv[1];
  268. PGresult   *res;
  269. int result_len;
  270. if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
  271. {
  272. if (lo_initialize(conn) < 0)
  273. return -1;
  274. }
  275. argv[0].isint = 1;
  276. argv[0].len = 4;
  277. argv[0].u.integer = fd;
  278. res = PQfn(conn, conn->lobjfuncs->fn_lo_tell,
  279.    &retval, &result_len, 1, argv, 1);
  280. if (PQresultStatus(res) == PGRES_COMMAND_OK)
  281. {
  282. PQclear(res);
  283. return retval;
  284. }
  285. else
  286. {
  287. PQclear(res);
  288. return -1;
  289. }
  290. }
  291. /*
  292.  * lo_unlink
  293.  *   delete a file
  294.  *
  295.  */
  296. int
  297. lo_unlink(PGconn *conn, Oid lobjId)
  298. {
  299. PQArgBlock argv[1];
  300. PGresult   *res;
  301. int result_len;
  302. int retval;
  303. if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
  304. {
  305. if (lo_initialize(conn) < 0)
  306. return -1;
  307. }
  308. argv[0].isint = 1;
  309. argv[0].len = 4;
  310. argv[0].u.integer = lobjId;
  311. res = PQfn(conn, conn->lobjfuncs->fn_lo_unlink,
  312.    &retval, &result_len, 1, argv, 1);
  313. if (PQresultStatus(res) == PGRES_COMMAND_OK)
  314. {
  315. PQclear(res);
  316. return retval;
  317. }
  318. else
  319. {
  320. PQclear(res);
  321. return -1;
  322. }
  323. }
  324. /*
  325.  * lo_import -
  326.  *   imports a file as an (inversion) large object.
  327.  * returns the oid of that object upon success,
  328.  * returns InvalidOid upon failure
  329.  *
  330.  */
  331. Oid
  332. lo_import(PGconn *conn, char *filename)
  333. {
  334. int fd;
  335. int nbytes,
  336. tmp;
  337. char buf[LO_BUFSIZE];
  338. Oid lobjOid;
  339. int lobj;
  340. /*
  341.  * open the file to be read in
  342.  */
  343. #ifndef __CYGWIN32__
  344. fd = open(filename, O_RDONLY, 0666);
  345. #else
  346. fd = open(filename, O_RDONLY | O_BINARY, 0666);
  347. #endif
  348. if (fd < 0)
  349. { /* error */
  350. sprintf(conn->errorMessage,
  351. "lo_import: can't open unix file"%s"n", filename);
  352. return InvalidOid;
  353. }
  354. /*
  355.  * create an inversion "object"
  356.  */
  357. lobjOid = lo_creat(conn, INV_READ | INV_WRITE);
  358. if (lobjOid == InvalidOid)
  359. {
  360. sprintf(conn->errorMessage,
  361.   "lo_import: can't create inv object for "%s"", filename);
  362. return InvalidOid;
  363. }
  364. lobj = lo_open(conn, lobjOid, INV_WRITE);
  365. if (lobj == -1)
  366. {
  367. sprintf(conn->errorMessage,
  368. "lo_import: could not open inv object oid %u", lobjOid);
  369. return InvalidOid;
  370. }
  371. /*
  372.  * read in from the Unix file and write to the inversion file
  373.  */
  374. while ((nbytes = read(fd, buf, LO_BUFSIZE)) > 0)
  375. {
  376. tmp = lo_write(conn, lobj, buf, nbytes);
  377. if (tmp < nbytes)
  378. {
  379. sprintf(conn->errorMessage,
  380. "lo_import: error while reading "%s"", filename);
  381. return InvalidOid;
  382. }
  383. }
  384. (void) close(fd);
  385. (void) lo_close(conn, lobj);
  386. return lobjOid;
  387. }
  388. /*
  389.  * lo_export -
  390.  *   exports an (inversion) large object.
  391.  * returns -1 upon failure, 1 otherwise
  392.  */
  393. int
  394. lo_export(PGconn *conn, Oid lobjId, char *filename)
  395. {
  396. int fd;
  397. int nbytes,
  398. tmp;
  399. char buf[LO_BUFSIZE];
  400. int lobj;
  401. /*
  402.  * create an inversion "object"
  403.  */
  404. lobj = lo_open(conn, lobjId, INV_READ);
  405. if (lobj == -1)
  406. {
  407. sprintf(conn->errorMessage,
  408. "lo_export: can't open inv object %u", lobjId);
  409. return -1;
  410. }
  411. /*
  412.  * open the file to be written to
  413.  */
  414. #ifndef __CYGWIN32__
  415. fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
  416. #else
  417. fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, 0666);
  418. #endif
  419. if (fd < 0)
  420. { /* error */
  421. sprintf(conn->errorMessage,
  422. "lo_export: can't open unix file"%s"", filename);
  423. return 0;
  424. }
  425. /*
  426.  * read in from the Unix file and write to the inversion file
  427.  */
  428. while ((nbytes = lo_read(conn, lobj, buf, LO_BUFSIZE)) > 0)
  429. {
  430. tmp = write(fd, buf, nbytes);
  431. if (tmp < nbytes)
  432. {
  433. sprintf(conn->errorMessage,
  434. "lo_export: error while writing "%s"",
  435. filename);
  436. return -1;
  437. }
  438. }
  439. (void) lo_close(conn, lobj);
  440. (void) close(fd);
  441. return 1;
  442. }
  443. /* ----------------
  444.  * lo_initialize
  445.  *
  446.  * Initialize the large object interface for an existing connection.
  447.  * We ask the backend about the functions OID's in pg_proc for all
  448.  * functions that are required for large object operations.
  449.  * ----------------
  450.  */
  451. static int
  452. lo_initialize(PGconn *conn)
  453. {
  454. PGresult   *res;
  455. PGlobjfuncs *lobjfuncs;
  456. int n;
  457. char    *fname;
  458. Oid foid;
  459. /* ----------------
  460.  * Allocate the structure to hold the functions OID's
  461.  * ----------------
  462.  */
  463. lobjfuncs = (PGlobjfuncs *) malloc(sizeof(PGlobjfuncs));
  464. if (lobjfuncs == (PGlobjfuncs *) NULL)
  465. {
  466. strcpy(conn->errorMessage,
  467.    "FATAL: malloc() failed in lo_initialize()n");
  468. return -1;
  469. }
  470. MemSet((char *) lobjfuncs, 0, sizeof(PGlobjfuncs));
  471. /* ----------------
  472.  * Execute the query to get all the functions at once
  473.  * ----------------
  474.  */
  475. res = PQexec(conn, "select proname, oid from pg_proc
  476.      where proname = 'lo_open'
  477.    or proname = 'lo_close'
  478.    or proname = 'lo_creat'
  479.    or proname = 'lo_unlink'
  480.    or proname = 'lo_lseek'
  481.    or proname = 'lo_tell'
  482.    or proname = 'loread'
  483.    or proname = 'lowrite'");
  484. if (res == (PGresult *) NULL)
  485. {
  486. free(lobjfuncs);
  487. return -1;
  488. }
  489. if (res->resultStatus != PGRES_TUPLES_OK)
  490. {
  491. free(lobjfuncs);
  492. PQclear(res);
  493. strcpy(conn->errorMessage,
  494.    "ERROR: SELECT didn't return data in lo_initialize()n");
  495. return -1;
  496. }
  497. /* ----------------
  498.  * Examine the result and put the OID's into the struct
  499.  * ----------------
  500.  */
  501. for (n = 0; n < PQntuples(res); n++)
  502. {
  503. fname = PQgetvalue(res, n, 0);
  504. foid = (Oid) atoi(PQgetvalue(res, n, 1));
  505. if (!strcmp(fname, "lo_open"))
  506. lobjfuncs->fn_lo_open = foid;
  507. else if (!strcmp(fname, "lo_close"))
  508. lobjfuncs->fn_lo_close = foid;
  509. else if (!strcmp(fname, "lo_creat"))
  510. lobjfuncs->fn_lo_creat = foid;
  511. else if (!strcmp(fname, "lo_unlink"))
  512. lobjfuncs->fn_lo_unlink = foid;
  513. else if (!strcmp(fname, "lo_lseek"))
  514. lobjfuncs->fn_lo_lseek = foid;
  515. else if (!strcmp(fname, "lo_tell"))
  516. lobjfuncs->fn_lo_tell = foid;
  517. else if (!strcmp(fname, "loread"))
  518. lobjfuncs->fn_lo_read = foid;
  519. else if (!strcmp(fname, "lowrite"))
  520. lobjfuncs->fn_lo_write = foid;
  521. }
  522. PQclear(res);
  523. /* ----------------
  524.  * Finally check that we really got all large object
  525.  * interface functions.
  526.  * ----------------
  527.  */
  528. if (lobjfuncs->fn_lo_open == 0)
  529. {
  530. strcpy(conn->errorMessage,
  531.    "ERROR: Cannot determine OID for function lo_openn");
  532. free(lobjfuncs);
  533. return -1;
  534. }
  535. if (lobjfuncs->fn_lo_close == 0)
  536. {
  537. strcpy(conn->errorMessage,
  538.    "ERROR: Cannot determine OID for function lo_closen");
  539. free(lobjfuncs);
  540. return -1;
  541. }
  542. if (lobjfuncs->fn_lo_creat == 0)
  543. {
  544. strcpy(conn->errorMessage,
  545.    "ERROR: Cannot determine OID for function lo_creatn");
  546. free(lobjfuncs);
  547. return -1;
  548. }
  549. if (lobjfuncs->fn_lo_unlink == 0)
  550. {
  551. strcpy(conn->errorMessage,
  552.    "ERROR: Cannot determine OID for function lo_unlinkn");
  553. free(lobjfuncs);
  554. return -1;
  555. }
  556. if (lobjfuncs->fn_lo_lseek == 0)
  557. {
  558. strcpy(conn->errorMessage,
  559.    "ERROR: Cannot determine OID for function lo_lseekn");
  560. free(lobjfuncs);
  561. return -1;
  562. }
  563. if (lobjfuncs->fn_lo_tell == 0)
  564. {
  565. strcpy(conn->errorMessage,
  566.    "ERROR: Cannot determine OID for function lo_telln");
  567. free(lobjfuncs);
  568. return -1;
  569. }
  570. if (lobjfuncs->fn_lo_read == 0)
  571. {
  572. strcpy(conn->errorMessage,
  573.    "ERROR: Cannot determine OID for function loreadn");
  574. free(lobjfuncs);
  575. return -1;
  576. }
  577. if (lobjfuncs->fn_lo_write == 0)
  578. {
  579. strcpy(conn->errorMessage,
  580.    "ERROR: Cannot determine OID for function lowriten");
  581. free(lobjfuncs);
  582. return -1;
  583. }
  584. /* ----------------
  585.  * Put the structure into the connection control
  586.  * ----------------
  587.  */
  588. conn->lobjfuncs = lobjfuncs;
  589. return 0;
  590. }