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

数据库系统

开发平台:

Unix_Linux

  1. /*
  2.  * PostgreSQL type definitions for managed LargeObjects.
  3.  *
  4.  * $Id: lo.c,v 1.2 1999/05/25 16:05:45 momjian Exp $
  5.  *
  6.  */
  7. #include <stdio.h>
  8. #include <postgres.h>
  9. #include <utils/palloc.h>
  10. /* Required for largeobjects */
  11. #include <libpq/libpq-fs.h>
  12. #include <libpq/be-fsstubs.h>
  13. /* Required for SPI */
  14. #include <executor/spi.h>
  15. /* Required for triggers */
  16. #include <commands/trigger.h>
  17. /* required for tolower() */
  18. /*
  19.  * This is the internal storage format for managed large objects
  20.  *
  21.  */
  22. typedef Oid Blob;
  23. /*
  24.  * Various forward declarations:
  25.  */
  26. Blob    *lo_in(char *str); /* Create from String */
  27. char    *lo_out(Blob * addr);/* Output oid as String */
  28. Oid lo_oid(Blob * addr);/* Return oid as an oid */
  29. Blob    *lo(Oid oid); /* Return Blob based on oid */
  30. HeapTuple lo_manage(void); /* Trigger handler */
  31. /*
  32.  * This creates a large object, and set's its OID to the value in the
  33.  * supplied string.
  34.  *
  35.  * If the string is empty, then a new LargeObject is created, and its oid
  36.  * is placed in the resulting lo.
  37.  */
  38. Blob *
  39. lo_in(char *str)
  40. {
  41. Blob    *result;
  42. Oid oid;
  43. int count;
  44. if (strlen(str) > 0)
  45. {
  46. count = sscanf(str, "%d", &oid);
  47. if (count < 1)
  48. {
  49. elog(ERROR, "lo_in: error in parsing "%s"", str);
  50. return (NULL);
  51. }
  52. if (oid < 0)
  53. {
  54. elog(ERROR, "lo_in: illegal oid "%s"", str);
  55. return (NULL);
  56. }
  57. }
  58. else
  59. {
  60. /*
  61.  * There is no Oid passed, so create a new one
  62.  */
  63. oid = lo_creat(INV_READ | INV_WRITE);
  64. if (oid == InvalidOid)
  65. {
  66. elog(ERROR, "lo_in: InvalidOid returned from lo_creat");
  67. return (NULL);
  68. }
  69. }
  70. result = (Blob *) palloc(sizeof(Blob));
  71. *result = oid;
  72. return (result);
  73. }
  74. /*
  75.  * This simply outputs the Oid of the Blob as a string.
  76.  */
  77. char *
  78. lo_out(Blob * addr)
  79. {
  80. char    *result;
  81. if (addr == NULL)
  82. return (NULL);
  83. result = (char *) palloc(32);
  84. sprintf(result, "%d", *addr);
  85. return (result);
  86. }
  87. /*
  88.  * This function converts Blob to oid.
  89.  *
  90.  * eg: select lo_export(raster::oid,'/path/file') from table;
  91.  *
  92.  */
  93. Oid
  94. lo_oid(Blob * addr)
  95. {
  96. if (addr == NULL)
  97. return InvalidOid;
  98. return (Oid) (*addr);
  99. }
  100. /*
  101.  * This function is used so we can convert oid's to lo's
  102.  *
  103.  * ie: insert into table values(lo_import('/path/file')::lo);
  104.  *
  105.  */
  106. Blob *
  107. lo(Oid oid)
  108. {
  109. Blob    *result = (Blob *) palloc(sizeof(Blob));
  110. *result = oid;
  111. return (result);
  112. }
  113. /*
  114.  * This handles the trigger that protects us from orphaned large objects
  115.  */
  116. HeapTuple
  117. lo_manage(void)
  118. {
  119. int attnum; /* attribute number to monitor */
  120. char   **args; /* Args containing attr name */
  121. TupleDesc tupdesc; /* Tuple Descriptor */
  122. HeapTuple rettuple; /* Tuple to be returned */
  123. bool isdelete; /* are we deleting? */
  124. HeapTuple newtuple = NULL;/* The new value for tuple */
  125. HeapTuple trigtuple; /* The original value of tuple */
  126. if (!CurrentTriggerData)
  127. elog(ERROR, "lo: triggers are not initialized");
  128. /*
  129.  * Fetch some values from CurrentTriggerData
  130.  */
  131. newtuple = CurrentTriggerData->tg_newtuple;
  132. trigtuple = CurrentTriggerData->tg_trigtuple;
  133. tupdesc = CurrentTriggerData->tg_relation->rd_att;
  134. args = CurrentTriggerData->tg_trigger->tgargs;
  135. /* tuple to return to Executor */
  136. if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event))
  137. rettuple = newtuple;
  138. else
  139. rettuple = trigtuple;
  140. /* Are we deleting the row? */
  141. isdelete = TRIGGER_FIRED_BY_DELETE(CurrentTriggerData->tg_event);
  142. /* Were done with it */
  143. CurrentTriggerData = NULL;
  144. /* Get the column were interested in */
  145. attnum = SPI_fnumber(tupdesc, args[0]);
  146. /*
  147.  * Handle updates
  148.  *
  149.  * Here, if the value of the monitored attribute changes, then the large
  150.  * object associated with the original value is unlinked.
  151.  */
  152. if (newtuple != NULL)
  153. {
  154. char    *orig = SPI_getvalue(trigtuple, tupdesc, attnum);
  155. char    *newv = SPI_getvalue(newtuple, tupdesc, attnum);
  156. if ((orig != newv && (orig == NULL || newv == NULL)) || (orig != NULL && newv != NULL && strcmp(orig, newv)))
  157. lo_unlink(atoi(orig));
  158. if (newv)
  159. pfree(newv);
  160. if (orig)
  161. pfree(orig);
  162. }
  163. /*
  164.  * Handle deleting of rows
  165.  *
  166.  * Here, we unlink the large object associated with the managed attribute
  167.  *
  168.  */
  169. if (isdelete)
  170. {
  171. char    *orig = SPI_getvalue(trigtuple, tupdesc, attnum);
  172. if (orig != NULL)
  173. {
  174. lo_unlink(atoi(orig));
  175. pfree(orig);
  176. }
  177. }
  178. return (rettuple);
  179. }