1 /*------------------------------------------------------------------------- 2 * 3 * fe-lobj.c 4 * Front-end large object interface 5 * 6 * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group 7 * Portions Copyright (c) 1994, Regents of the University of California 8 * 9 * 10 * IDENTIFICATION 11 * src/interfaces/libpq/fe-lobj.c 12 * 13 *------------------------------------------------------------------------- 14 */ 15 16 #ifdef WIN32 17 /* 18 * As unlink/rename are #define'd in port.h (via postgres_fe.h), io.h 19 * must be included first on MS C. Might as well do it for all WIN32's 20 * here. 21 */ 22 #include <io.h> 23 #endif 24 25 #include "postgres_fe.h" 26 27 #ifdef WIN32 28 #include "win32.h" 29 #else 30 #include <unistd.h> 31 #endif 32 33 #include <fcntl.h> 34 #include <limits.h> 35 #include <sys/stat.h> 36 37 #include "libpq-fe.h" 38 #include "libpq-int.h" 39 #include "libpq/libpq-fs.h" /* must come after sys/stat.h */ 40 #include "port/pg_bswap.h" 41 42 #define LO_BUFSIZE 8192 43 44 static int lo_initialize(PGconn *conn); 45 static Oid lo_import_internal(PGconn *conn, const char *filename, Oid oid); 46 static pg_int64 lo_hton64(pg_int64 host64); 47 static pg_int64 lo_ntoh64(pg_int64 net64); 48 49 /* 50 * lo_open 51 * opens an existing large object 52 * 53 * returns the file descriptor for use in later lo_* calls 54 * return -1 upon failure. 55 */ 56 int 57 lo_open(PGconn *conn, Oid lobjId, int mode) 58 { 59 int fd; 60 int result_len; 61 PQArgBlock argv[2]; 62 PGresult *res; 63 64 if (conn == NULL || conn->lobjfuncs == NULL) 65 { 66 if (lo_initialize(conn) < 0) 67 return -1; 68 } 69 70 argv[0].isint = 1; 71 argv[0].len = 4; 72 argv[0].u.integer = lobjId; 73 74 argv[1].isint = 1; 75 argv[1].len = 4; 76 argv[1].u.integer = mode; 77 78 res = PQfn(conn, conn->lobjfuncs->fn_lo_open, &fd, &result_len, 1, argv, 2); 79 if (PQresultStatus(res) == PGRES_COMMAND_OK) 80 { 81 PQclear(res); 82 return fd; 83 } 84 else 85 { 86 PQclear(res); 87 return -1; 88 } 89 } 90 91 /* 92 * lo_close 93 * closes an existing large object 94 * 95 * returns 0 upon success 96 * returns -1 upon failure. 97 */ 98 int 99 lo_close(PGconn *conn, int fd) 100 { 101 PQArgBlock argv[1]; 102 PGresult *res; 103 int retval; 104 int result_len; 105 106 if (conn == NULL || conn->lobjfuncs == NULL) 107 { 108 if (lo_initialize(conn) < 0) 109 return -1; 110 } 111 112 argv[0].isint = 1; 113 argv[0].len = 4; 114 argv[0].u.integer = fd; 115 res = PQfn(conn, conn->lobjfuncs->fn_lo_close, 116 &retval, &result_len, 1, argv, 1); 117 if (PQresultStatus(res) == PGRES_COMMAND_OK) 118 { 119 PQclear(res); 120 return retval; 121 } 122 else 123 { 124 PQclear(res); 125 return -1; 126 } 127 } 128 129 /* 130 * lo_truncate 131 * truncates an existing large object to the given size 132 * 133 * returns 0 upon success 134 * returns -1 upon failure 135 */ 136 int 137 lo_truncate(PGconn *conn, int fd, size_t len) 138 { 139 PQArgBlock argv[2]; 140 PGresult *res; 141 int retval; 142 int result_len; 143 144 if (conn == NULL || conn->lobjfuncs == NULL) 145 { 146 if (lo_initialize(conn) < 0) 147 return -1; 148 } 149 150 /* Must check this on-the-fly because it's not there pre-8.3 */ 151 if (conn->lobjfuncs->fn_lo_truncate == 0) 152 { 153 printfPQExpBuffer(&conn->errorMessage, 154 libpq_gettext("cannot determine OID of function lo_truncate\n")); 155 return -1; 156 } 157 158 /* 159 * Long ago, somebody thought it'd be a good idea to declare this function 160 * as taking size_t ... but the underlying backend function only accepts a 161 * signed int32 length. So throw error if the given value overflows 162 * int32. (A possible alternative is to automatically redirect the call 163 * to lo_truncate64; but if the caller wanted to rely on that backend 164 * function being available, he could have called lo_truncate64 for 165 * himself.) 166 */ 167 if (len > (size_t) INT_MAX) 168 { 169 printfPQExpBuffer(&conn->errorMessage, 170 libpq_gettext("argument of lo_truncate exceeds integer range\n")); 171 return -1; 172 } 173 174 argv[0].isint = 1; 175 argv[0].len = 4; 176 argv[0].u.integer = fd; 177 178 argv[1].isint = 1; 179 argv[1].len = 4; 180 argv[1].u.integer = (int) len; 181 182 res = PQfn(conn, conn->lobjfuncs->fn_lo_truncate, 183 &retval, &result_len, 1, argv, 2); 184 185 if (PQresultStatus(res) == PGRES_COMMAND_OK) 186 { 187 PQclear(res); 188 return retval; 189 } 190 else 191 { 192 PQclear(res); 193 return -1; 194 } 195 } 196 197 /* 198 * lo_truncate64 199 * truncates an existing large object to the given size 200 * 201 * returns 0 upon success 202 * returns -1 upon failure 203 */ 204 int 205 lo_truncate64(PGconn *conn, int fd, pg_int64 len) 206 { 207 PQArgBlock argv[2]; 208 PGresult *res; 209 int retval; 210 int result_len; 211 212 if (conn == NULL || conn->lobjfuncs == NULL) 213 { 214 if (lo_initialize(conn) < 0) 215 return -1; 216 } 217 218 if (conn->lobjfuncs->fn_lo_truncate64 == 0) 219 { 220 printfPQExpBuffer(&conn->errorMessage, 221 libpq_gettext("cannot determine OID of function lo_truncate64\n")); 222 return -1; 223 } 224 225 argv[0].isint = 1; 226 argv[0].len = 4; 227 argv[0].u.integer = fd; 228 229 len = lo_hton64(len); 230 argv[1].isint = 0; 231 argv[1].len = 8; 232 argv[1].u.ptr = (int *) &len; 233 234 res = PQfn(conn, conn->lobjfuncs->fn_lo_truncate64, 235 &retval, &result_len, 1, argv, 2); 236 237 if (PQresultStatus(res) == PGRES_COMMAND_OK) 238 { 239 PQclear(res); 240 return retval; 241 } 242 else 243 { 244 PQclear(res); 245 return -1; 246 } 247 } 248 249 /* 250 * lo_read 251 * read len bytes of the large object into buf 252 * 253 * returns the number of bytes read, or -1 on failure. 254 * the CALLER must have allocated enough space to hold the result returned 255 */ 256 257 int 258 lo_read(PGconn *conn, int fd, char *buf, size_t len) 259 { 260 PQArgBlock argv[2]; 261 PGresult *res; 262 int result_len; 263 264 if (conn == NULL || conn->lobjfuncs == NULL) 265 { 266 if (lo_initialize(conn) < 0) 267 return -1; 268 } 269 270 /* 271 * Long ago, somebody thought it'd be a good idea to declare this function 272 * as taking size_t ... but the underlying backend function only accepts a 273 * signed int32 length. So throw error if the given value overflows 274 * int32. 275 */ 276 if (len > (size_t) INT_MAX) 277 { 278 printfPQExpBuffer(&conn->errorMessage, 279 libpq_gettext("argument of lo_read exceeds integer range\n")); 280 return -1; 281 } 282 283 argv[0].isint = 1; 284 argv[0].len = 4; 285 argv[0].u.integer = fd; 286 287 argv[1].isint = 1; 288 argv[1].len = 4; 289 argv[1].u.integer = (int) len; 290 291 res = PQfn(conn, conn->lobjfuncs->fn_lo_read, 292 (void *) buf, &result_len, 0, argv, 2); 293 if (PQresultStatus(res) == PGRES_COMMAND_OK) 294 { 295 PQclear(res); 296 return result_len; 297 } 298 else 299 { 300 PQclear(res); 301 return -1; 302 } 303 } 304 305 /* 306 * lo_write 307 * write len bytes of buf into the large object fd 308 * 309 * returns the number of bytes written, or -1 on failure. 310 */ 311 int 312 lo_write(PGconn *conn, int fd, const char *buf, size_t len) 313 { 314 PQArgBlock argv[2]; 315 PGresult *res; 316 int result_len; 317 int retval; 318 319 if (conn == NULL || conn->lobjfuncs == NULL) 320 { 321 if (lo_initialize(conn) < 0) 322 return -1; 323 } 324 325 /* 326 * Long ago, somebody thought it'd be a good idea to declare this function 327 * as taking size_t ... but the underlying backend function only accepts a 328 * signed int32 length. So throw error if the given value overflows 329 * int32. 330 */ 331 if (len > (size_t) INT_MAX) 332 { 333 printfPQExpBuffer(&conn->errorMessage, 334 libpq_gettext("argument of lo_write exceeds integer range\n")); 335 return -1; 336 } 337 338 argv[0].isint = 1; 339 argv[0].len = 4; 340 argv[0].u.integer = fd; 341 342 argv[1].isint = 0; 343 argv[1].len = (int) len; 344 argv[1].u.ptr = (int *) buf; 345 346 res = PQfn(conn, conn->lobjfuncs->fn_lo_write, 347 &retval, &result_len, 1, argv, 2); 348 if (PQresultStatus(res) == PGRES_COMMAND_OK) 349 { 350 PQclear(res); 351 return retval; 352 } 353 else 354 { 355 PQclear(res); 356 return -1; 357 } 358 } 359 360 /* 361 * lo_lseek 362 * change the current read or write location on a large object 363 */ 364 int 365 lo_lseek(PGconn *conn, int fd, int offset, int whence) 366 { 367 PQArgBlock argv[3]; 368 PGresult *res; 369 int retval; 370 int result_len; 371 372 if (conn == NULL || conn->lobjfuncs == NULL) 373 { 374 if (lo_initialize(conn) < 0) 375 return -1; 376 } 377 378 argv[0].isint = 1; 379 argv[0].len = 4; 380 argv[0].u.integer = fd; 381 382 argv[1].isint = 1; 383 argv[1].len = 4; 384 argv[1].u.integer = offset; 385 386 argv[2].isint = 1; 387 argv[2].len = 4; 388 argv[2].u.integer = whence; 389 390 res = PQfn(conn, conn->lobjfuncs->fn_lo_lseek, 391 &retval, &result_len, 1, argv, 3); 392 if (PQresultStatus(res) == PGRES_COMMAND_OK) 393 { 394 PQclear(res); 395 return retval; 396 } 397 else 398 { 399 PQclear(res); 400 return -1; 401 } 402 } 403 404 /* 405 * lo_lseek64 406 * change the current read or write location on a large object 407 */ 408 pg_int64 409 lo_lseek64(PGconn *conn, int fd, pg_int64 offset, int whence) 410 { 411 PQArgBlock argv[3]; 412 PGresult *res; 413 pg_int64 retval; 414 int result_len; 415 416 if (conn == NULL || conn->lobjfuncs == NULL) 417 { 418 if (lo_initialize(conn) < 0) 419 return -1; 420 } 421 422 if (conn->lobjfuncs->fn_lo_lseek64 == 0) 423 { 424 printfPQExpBuffer(&conn->errorMessage, 425 libpq_gettext("cannot determine OID of function lo_lseek64\n")); 426 return -1; 427 } 428 429 argv[0].isint = 1; 430 argv[0].len = 4; 431 argv[0].u.integer = fd; 432 433 offset = lo_hton64(offset); 434 argv[1].isint = 0; 435 argv[1].len = 8; 436 argv[1].u.ptr = (int *) &offset; 437 438 argv[2].isint = 1; 439 argv[2].len = 4; 440 argv[2].u.integer = whence; 441 442 res = PQfn(conn, conn->lobjfuncs->fn_lo_lseek64, 443 (void *) &retval, &result_len, 0, argv, 3); 444 if (PQresultStatus(res) == PGRES_COMMAND_OK && result_len == 8) 445 { 446 PQclear(res); 447 return lo_ntoh64(retval); 448 } 449 else 450 { 451 PQclear(res); 452 return -1; 453 } 454 } 455 456 /* 457 * lo_creat 458 * create a new large object 459 * the mode is ignored (once upon a time it had a use) 460 * 461 * returns the oid of the large object created or 462 * InvalidOid upon failure 463 */ 464 Oid 465 lo_creat(PGconn *conn, int mode) 466 { 467 PQArgBlock argv[1]; 468 PGresult *res; 469 int retval; 470 int result_len; 471 472 if (conn == NULL || conn->lobjfuncs == NULL) 473 { 474 if (lo_initialize(conn) < 0) 475 return InvalidOid; 476 } 477 478 argv[0].isint = 1; 479 argv[0].len = 4; 480 argv[0].u.integer = mode; 481 res = PQfn(conn, conn->lobjfuncs->fn_lo_creat, 482 &retval, &result_len, 1, argv, 1); 483 if (PQresultStatus(res) == PGRES_COMMAND_OK) 484 { 485 PQclear(res); 486 return (Oid) retval; 487 } 488 else 489 { 490 PQclear(res); 491 return InvalidOid; 492 } 493 } 494 495 /* 496 * lo_create 497 * create a new large object 498 * if lobjId isn't InvalidOid, it specifies the OID to (attempt to) create 499 * 500 * returns the oid of the large object created or 501 * InvalidOid upon failure 502 */ 503 Oid 504 lo_create(PGconn *conn, Oid lobjId) 505 { 506 PQArgBlock argv[1]; 507 PGresult *res; 508 int retval; 509 int result_len; 510 511 if (conn == NULL || conn->lobjfuncs == NULL) 512 { 513 if (lo_initialize(conn) < 0) 514 return InvalidOid; 515 } 516 517 /* Must check this on-the-fly because it's not there pre-8.1 */ 518 if (conn->lobjfuncs->fn_lo_create == 0) 519 { 520 printfPQExpBuffer(&conn->errorMessage, 521 libpq_gettext("cannot determine OID of function lo_create\n")); 522 return InvalidOid; 523 } 524 525 argv[0].isint = 1; 526 argv[0].len = 4; 527 argv[0].u.integer = lobjId; 528 res = PQfn(conn, conn->lobjfuncs->fn_lo_create, 529 &retval, &result_len, 1, argv, 1); 530 if (PQresultStatus(res) == PGRES_COMMAND_OK) 531 { 532 PQclear(res); 533 return (Oid) retval; 534 } 535 else 536 { 537 PQclear(res); 538 return InvalidOid; 539 } 540 } 541 542 543 /* 544 * lo_tell 545 * returns the current seek location of the large object 546 */ 547 int 548 lo_tell(PGconn *conn, int fd) 549 { 550 int retval; 551 PQArgBlock argv[1]; 552 PGresult *res; 553 int result_len; 554 555 if (conn == NULL || conn->lobjfuncs == NULL) 556 { 557 if (lo_initialize(conn) < 0) 558 return -1; 559 } 560 561 argv[0].isint = 1; 562 argv[0].len = 4; 563 argv[0].u.integer = fd; 564 565 res = PQfn(conn, conn->lobjfuncs->fn_lo_tell, 566 &retval, &result_len, 1, argv, 1); 567 if (PQresultStatus(res) == PGRES_COMMAND_OK) 568 { 569 PQclear(res); 570 return retval; 571 } 572 else 573 { 574 PQclear(res); 575 return -1; 576 } 577 } 578 579 /* 580 * lo_tell64 581 * returns the current seek location of the large object 582 */ 583 pg_int64 584 lo_tell64(PGconn *conn, int fd) 585 { 586 pg_int64 retval; 587 PQArgBlock argv[1]; 588 PGresult *res; 589 int result_len; 590 591 if (conn == NULL || conn->lobjfuncs == NULL) 592 { 593 if (lo_initialize(conn) < 0) 594 return -1; 595 } 596 597 if (conn->lobjfuncs->fn_lo_tell64 == 0) 598 { 599 printfPQExpBuffer(&conn->errorMessage, 600 libpq_gettext("cannot determine OID of function lo_tell64\n")); 601 return -1; 602 } 603 604 argv[0].isint = 1; 605 argv[0].len = 4; 606 argv[0].u.integer = fd; 607 608 res = PQfn(conn, conn->lobjfuncs->fn_lo_tell64, 609 (void *) &retval, &result_len, 0, argv, 1); 610 if (PQresultStatus(res) == PGRES_COMMAND_OK && result_len == 8) 611 { 612 PQclear(res); 613 return lo_ntoh64(retval); 614 } 615 else 616 { 617 PQclear(res); 618 return -1; 619 } 620 } 621 622 /* 623 * lo_unlink 624 * delete a file 625 */ 626 627 int 628 lo_unlink(PGconn *conn, Oid lobjId) 629 { 630 PQArgBlock argv[1]; 631 PGresult *res; 632 int result_len; 633 int retval; 634 635 if (conn == NULL || conn->lobjfuncs == NULL) 636 { 637 if (lo_initialize(conn) < 0) 638 return -1; 639 } 640 641 argv[0].isint = 1; 642 argv[0].len = 4; 643 argv[0].u.integer = lobjId; 644 645 res = PQfn(conn, conn->lobjfuncs->fn_lo_unlink, 646 &retval, &result_len, 1, argv, 1); 647 if (PQresultStatus(res) == PGRES_COMMAND_OK) 648 { 649 PQclear(res); 650 return retval; 651 } 652 else 653 { 654 PQclear(res); 655 return -1; 656 } 657 } 658 659 /* 660 * lo_import - 661 * imports a file as an (inversion) large object. 662 * 663 * returns the oid of that object upon success, 664 * returns InvalidOid upon failure 665 */ 666 667 Oid 668 lo_import(PGconn *conn, const char *filename) 669 { 670 return lo_import_internal(conn, filename, InvalidOid); 671 } 672 673 /* 674 * lo_import_with_oid - 675 * imports a file as an (inversion) large object. 676 * large object id can be specified. 677 * 678 * returns the oid of that object upon success, 679 * returns InvalidOid upon failure 680 */ 681 682 Oid 683 lo_import_with_oid(PGconn *conn, const char *filename, Oid lobjId) 684 { 685 return lo_import_internal(conn, filename, lobjId); 686 } 687 688 static Oid 689 lo_import_internal(PGconn *conn, const char *filename, Oid oid) 690 { 691 int fd; 692 int nbytes, 693 tmp; 694 char buf[LO_BUFSIZE]; 695 Oid lobjOid; 696 int lobj; 697 char sebuf[256]; 698 699 /* 700 * open the file to be read in 701 */ 702 fd = open(filename, O_RDONLY | PG_BINARY, 0666); 703 if (fd < 0) 704 { /* error */ 705 printfPQExpBuffer(&conn->errorMessage, 706 libpq_gettext("could not open file \"%s\": %s\n"), 707 filename, pqStrerror(errno, sebuf, sizeof(sebuf))); 708 return InvalidOid; 709 } 710 711 /* 712 * create an inversion object 713 */ 714 if (oid == InvalidOid) 715 lobjOid = lo_creat(conn, INV_READ | INV_WRITE); 716 else 717 lobjOid = lo_create(conn, oid); 718 719 if (lobjOid == InvalidOid) 720 { 721 /* we assume lo_create() already set a suitable error message */ 722 (void) close(fd); 723 return InvalidOid; 724 } 725 726 lobj = lo_open(conn, lobjOid, INV_WRITE); 727 if (lobj == -1) 728 { 729 /* we assume lo_open() already set a suitable error message */ 730 (void) close(fd); 731 return InvalidOid; 732 } 733 734 /* 735 * read in from the file and write to the large object 736 */ 737 while ((nbytes = read(fd, buf, LO_BUFSIZE)) > 0) 738 { 739 tmp = lo_write(conn, lobj, buf, nbytes); 740 if (tmp != nbytes) 741 { 742 /* 743 * If lo_write() failed, we are now in an aborted transaction so 744 * there's no need for lo_close(); furthermore, if we tried it 745 * we'd overwrite the useful error result with a useless one. So 746 * just nail the doors shut and get out of town. 747 */ 748 (void) close(fd); 749 return InvalidOid; 750 } 751 } 752 753 if (nbytes < 0) 754 { 755 /* We must do lo_close before setting the errorMessage */ 756 int save_errno = errno; 757 758 (void) lo_close(conn, lobj); 759 (void) close(fd); 760 printfPQExpBuffer(&conn->errorMessage, 761 libpq_gettext("could not read from file \"%s\": %s\n"), 762 filename, 763 pqStrerror(save_errno, sebuf, sizeof(sebuf))); 764 return InvalidOid; 765 } 766 767 (void) close(fd); 768 769 if (lo_close(conn, lobj) != 0) 770 { 771 /* we assume lo_close() already set a suitable error message */ 772 return InvalidOid; 773 } 774 775 return lobjOid; 776 } 777 778 /* 779 * lo_export - 780 * exports an (inversion) large object. 781 * returns -1 upon failure, 1 if OK 782 */ 783 int 784 lo_export(PGconn *conn, Oid lobjId, const char *filename) 785 { 786 int result = 1; 787 int fd; 788 int nbytes, 789 tmp; 790 char buf[LO_BUFSIZE]; 791 int lobj; 792 char sebuf[256]; 793 794 /* 795 * open the large object. 796 */ 797 lobj = lo_open(conn, lobjId, INV_READ); 798 if (lobj == -1) 799 { 800 /* we assume lo_open() already set a suitable error message */ 801 return -1; 802 } 803 804 /* 805 * create the file to be written to 806 */ 807 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | PG_BINARY, 0666); 808 if (fd < 0) 809 { 810 /* We must do lo_close before setting the errorMessage */ 811 int save_errno = errno; 812 813 (void) lo_close(conn, lobj); 814 printfPQExpBuffer(&conn->errorMessage, 815 libpq_gettext("could not open file \"%s\": %s\n"), 816 filename, 817 pqStrerror(save_errno, sebuf, sizeof(sebuf))); 818 return -1; 819 } 820 821 /* 822 * read in from the large object and write to the file 823 */ 824 while ((nbytes = lo_read(conn, lobj, buf, LO_BUFSIZE)) > 0) 825 { 826 tmp = write(fd, buf, nbytes); 827 if (tmp != nbytes) 828 { 829 /* We must do lo_close before setting the errorMessage */ 830 int save_errno = errno; 831 832 (void) lo_close(conn, lobj); 833 (void) close(fd); 834 printfPQExpBuffer(&conn->errorMessage, 835 libpq_gettext("could not write to file \"%s\": %s\n"), 836 filename, 837 pqStrerror(save_errno, sebuf, sizeof(sebuf))); 838 return -1; 839 } 840 } 841 842 /* 843 * If lo_read() failed, we are now in an aborted transaction so there's no 844 * need for lo_close(); furthermore, if we tried it we'd overwrite the 845 * useful error result with a useless one. So skip lo_close() if we got a 846 * failure result. 847 */ 848 if (nbytes < 0 || 849 lo_close(conn, lobj) != 0) 850 { 851 /* assume lo_read() or lo_close() left a suitable error message */ 852 result = -1; 853 } 854 855 /* if we already failed, don't overwrite that msg with a close error */ 856 if (close(fd) && result >= 0) 857 { 858 printfPQExpBuffer(&conn->errorMessage, 859 libpq_gettext("could not write to file \"%s\": %s\n"), 860 filename, pqStrerror(errno, sebuf, sizeof(sebuf))); 861 result = -1; 862 } 863 864 return result; 865 } 866 867 868 /* 869 * lo_initialize 870 * 871 * Initialize the large object interface for an existing connection. 872 * We ask the backend about the functions OID's in pg_proc for all 873 * functions that are required for large object operations. 874 */ 875 static int 876 lo_initialize(PGconn *conn) 877 { 878 PGresult *res; 879 PGlobjfuncs *lobjfuncs; 880 int n; 881 const char *query; 882 const char *fname; 883 Oid foid; 884 885 if (!conn) 886 return -1; 887 888 /* 889 * Allocate the structure to hold the functions OID's 890 */ 891 lobjfuncs = (PGlobjfuncs *) malloc(sizeof(PGlobjfuncs)); 892 if (lobjfuncs == NULL) 893 { 894 printfPQExpBuffer(&conn->errorMessage, 895 libpq_gettext("out of memory\n")); 896 return -1; 897 } 898 MemSet((char *) lobjfuncs, 0, sizeof(PGlobjfuncs)); 899 900 /* 901 * Execute the query to get all the functions at once. In 7.3 and later 902 * we need to be schema-safe. lo_create only exists in 8.1 and up. 903 * lo_truncate only exists in 8.3 and up. 904 */ 905 if (conn->sversion >= 70300) 906 query = "select proname, oid from pg_catalog.pg_proc " 907 "where proname in (" 908 "'lo_open', " 909 "'lo_close', " 910 "'lo_creat', " 911 "'lo_create', " 912 "'lo_unlink', " 913 "'lo_lseek', " 914 "'lo_lseek64', " 915 "'lo_tell', " 916 "'lo_tell64', " 917 "'lo_truncate', " 918 "'lo_truncate64', " 919 "'loread', " 920 "'lowrite') " 921 "and pronamespace = (select oid from pg_catalog.pg_namespace " 922 "where nspname = 'pg_catalog')"; 923 else 924 query = "select proname, oid from pg_proc " 925 "where proname = 'lo_open' " 926 "or proname = 'lo_close' " 927 "or proname = 'lo_creat' " 928 "or proname = 'lo_unlink' " 929 "or proname = 'lo_lseek' " 930 "or proname = 'lo_tell' " 931 "or proname = 'loread' " 932 "or proname = 'lowrite'"; 933 934 res = PQexec(conn, query); 935 if (res == NULL) 936 { 937 free(lobjfuncs); 938 return -1; 939 } 940 941 if (res->resultStatus != PGRES_TUPLES_OK) 942 { 943 free(lobjfuncs); 944 PQclear(res); 945 printfPQExpBuffer(&conn->errorMessage, 946 libpq_gettext("query to initialize large object functions did not return data\n")); 947 return -1; 948 } 949 950 /* 951 * Examine the result and put the OID's into the struct 952 */ 953 for (n = 0; n < PQntuples(res); n++) 954 { 955 fname = PQgetvalue(res, n, 0); 956 foid = (Oid) atoi(PQgetvalue(res, n, 1)); 957 if (strcmp(fname, "lo_open") == 0) 958 lobjfuncs->fn_lo_open = foid; 959 else if (strcmp(fname, "lo_close") == 0) 960 lobjfuncs->fn_lo_close = foid; 961 else if (strcmp(fname, "lo_creat") == 0) 962 lobjfuncs->fn_lo_creat = foid; 963 else if (strcmp(fname, "lo_create") == 0) 964 lobjfuncs->fn_lo_create = foid; 965 else if (strcmp(fname, "lo_unlink") == 0) 966 lobjfuncs->fn_lo_unlink = foid; 967 else if (strcmp(fname, "lo_lseek") == 0) 968 lobjfuncs->fn_lo_lseek = foid; 969 else if (strcmp(fname, "lo_lseek64") == 0) 970 lobjfuncs->fn_lo_lseek64 = foid; 971 else if (strcmp(fname, "lo_tell") == 0) 972 lobjfuncs->fn_lo_tell = foid; 973 else if (strcmp(fname, "lo_tell64") == 0) 974 lobjfuncs->fn_lo_tell64 = foid; 975 else if (strcmp(fname, "lo_truncate") == 0) 976 lobjfuncs->fn_lo_truncate = foid; 977 else if (strcmp(fname, "lo_truncate64") == 0) 978 lobjfuncs->fn_lo_truncate64 = foid; 979 else if (strcmp(fname, "loread") == 0) 980 lobjfuncs->fn_lo_read = foid; 981 else if (strcmp(fname, "lowrite") == 0) 982 lobjfuncs->fn_lo_write = foid; 983 } 984 985 PQclear(res); 986 987 /* 988 * Finally check that we got all required large object interface functions 989 * (ones that have been added later than the stone age are instead checked 990 * only if used) 991 */ 992 if (lobjfuncs->fn_lo_open == 0) 993 { 994 printfPQExpBuffer(&conn->errorMessage, 995 libpq_gettext("cannot determine OID of function lo_open\n")); 996 free(lobjfuncs); 997 return -1; 998 } 999 if (lobjfuncs->fn_lo_close == 0) 1000 { 1001 printfPQExpBuffer(&conn->errorMessage, 1002 libpq_gettext("cannot determine OID of function lo_close\n")); 1003 free(lobjfuncs); 1004 return -1; 1005 } 1006 if (lobjfuncs->fn_lo_creat == 0) 1007 { 1008 printfPQExpBuffer(&conn->errorMessage, 1009 libpq_gettext("cannot determine OID of function lo_creat\n")); 1010 free(lobjfuncs); 1011 return -1; 1012 } 1013 if (lobjfuncs->fn_lo_unlink == 0) 1014 { 1015 printfPQExpBuffer(&conn->errorMessage, 1016 libpq_gettext("cannot determine OID of function lo_unlink\n")); 1017 free(lobjfuncs); 1018 return -1; 1019 } 1020 if (lobjfuncs->fn_lo_lseek == 0) 1021 { 1022 printfPQExpBuffer(&conn->errorMessage, 1023 libpq_gettext("cannot determine OID of function lo_lseek\n")); 1024 free(lobjfuncs); 1025 return -1; 1026 } 1027 if (lobjfuncs->fn_lo_tell == 0) 1028 { 1029 printfPQExpBuffer(&conn->errorMessage, 1030 libpq_gettext("cannot determine OID of function lo_tell\n")); 1031 free(lobjfuncs); 1032 return -1; 1033 } 1034 if (lobjfuncs->fn_lo_read == 0) 1035 { 1036 printfPQExpBuffer(&conn->errorMessage, 1037 libpq_gettext("cannot determine OID of function loread\n")); 1038 free(lobjfuncs); 1039 return -1; 1040 } 1041 if (lobjfuncs->fn_lo_write == 0) 1042 { 1043 printfPQExpBuffer(&conn->errorMessage, 1044 libpq_gettext("cannot determine OID of function lowrite\n")); 1045 free(lobjfuncs); 1046 return -1; 1047 } 1048 1049 /* 1050 * Put the structure into the connection control 1051 */ 1052 conn->lobjfuncs = lobjfuncs; 1053 return 0; 1054 } 1055 1056 /* 1057 * lo_hton64 1058 * converts a 64-bit integer from host byte order to network byte order 1059 */ 1060 static pg_int64 1061 lo_hton64(pg_int64 host64) 1062 { 1063 union 1064 { 1065 pg_int64 i64; 1066 uint32 i32[2]; 1067 } swap; 1068 uint32 t; 1069 1070 /* High order half first, since we're doing MSB-first */ 1071 t = (uint32) (host64 >> 32); 1072 swap.i32[0] = pg_hton32(t); 1073 1074 /* Now the low order half */ 1075 t = (uint32) host64; 1076 swap.i32[1] = pg_hton32(t); 1077 1078 return swap.i64; 1079 } 1080 1081 /* 1082 * lo_ntoh64 1083 * converts a 64-bit integer from network byte order to host byte order 1084 */ 1085 static pg_int64 1086 lo_ntoh64(pg_int64 net64) 1087 { 1088 union 1089 { 1090 pg_int64 i64; 1091 uint32 i32[2]; 1092 } swap; 1093 pg_int64 result; 1094 1095 swap.i64 = net64; 1096 1097 result = (uint32) pg_ntoh32(swap.i32[0]); 1098 result <<= 32; 1099 result |= (uint32) pg_ntoh32(swap.i32[1]); 1100 1101 return result; 1102 } 1103