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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * pg_aggregate.c
  4.  *   routines to support manipulation of the pg_aggregate relation
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.20.2.1 1999/08/02 05:56:55 scrappy Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. #include "postgres.h"
  15. #include "access/heapam.h"
  16. #include "catalog/catname.h"
  17. #include "catalog/pg_aggregate.h"
  18. #include "catalog/pg_proc.h"
  19. #include "catalog/pg_type.h"
  20. #include "miscadmin.h"
  21. #include "utils/builtins.h"
  22. #include "utils/syscache.h"
  23. /* ----------------
  24.  * AggregateCreate
  25.  *
  26.  * aggregates overloading has been added.  Instead of the full
  27.  * overload support we have for functions, aggregate overloading only
  28.  * applies to exact basetype matches.  That is, we don't check the
  29.  * the inheritance hierarchy
  30.  *
  31.  * OLD COMMENTS:
  32.  * Currently, redefining aggregates using the same name is not
  33.  * supported. In such a case, a warning is printed that the
  34.  * aggregate already exists.  If such is not the case, a new tuple
  35.  * is created and inserted in the aggregate relation. The fields
  36.  * of this tuple are aggregate name, owner id, 2 transition functions
  37.  * (called aggtransfn1 and aggtransfn2), final function (aggfinalfn),
  38.  * type of data on which aggtransfn1 operates (aggbasetype), return
  39.  * types of the two transition functions (aggtranstype1 and
  40.  * aggtranstype2), final return type (aggfinaltype), and initial values
  41.  * for the two state transition functions (agginitval1 and agginitval2).
  42.  * All types and functions must have been defined
  43.  * prior to defining the aggregate.
  44.  *
  45.  * ---------------
  46.  */
  47. void
  48. AggregateCreate(char *aggName,
  49. char *aggtransfn1Name,
  50. char *aggtransfn2Name,
  51. char *aggfinalfnName,
  52. char *aggbasetypeName,
  53. char *aggtransfn1typeName,
  54. char *aggtransfn2typeName,
  55. char *agginitval1,
  56. char *agginitval2)
  57. {
  58. int i;
  59. Relation aggdesc;
  60. HeapTuple tup;
  61. char nulls[Natts_pg_aggregate];
  62. Datum values[Natts_pg_aggregate];
  63. Form_pg_proc proc;
  64. Oid xfn1 = InvalidOid;
  65. Oid xfn2 = InvalidOid;
  66. Oid ffn = InvalidOid;
  67. Oid xbase = InvalidOid;
  68. Oid xret1 = InvalidOid;
  69. Oid xret2 = InvalidOid;
  70. Oid fret = InvalidOid;
  71. Oid fnArgs[8];
  72. NameData aname;
  73. TupleDesc tupDesc;
  74. MemSet(fnArgs, 0, 8 * sizeof(Oid));
  75. /* sanity checks */
  76. if (!aggName)
  77. elog(ERROR, "AggregateCreate: no aggregate name supplied");
  78. if (!aggtransfn1Name && !aggtransfn2Name)
  79. elog(ERROR, "AggregateCreate: aggregate must have at least one transition function");
  80. tup = SearchSysCacheTuple(TYPNAME,
  81.   PointerGetDatum(aggbasetypeName),
  82.   0, 0, 0);
  83. if (!HeapTupleIsValid(tup))
  84. elog(ERROR, "AggregateCreate: Type '%s' undefined", aggbasetypeName);
  85. xbase = tup->t_data->t_oid;
  86. if (aggtransfn1Name)
  87. {
  88. tup = SearchSysCacheTuple(TYPNAME,
  89.   PointerGetDatum(aggtransfn1typeName),
  90.   0, 0, 0);
  91. if (!HeapTupleIsValid(tup))
  92. elog(ERROR, "AggregateCreate: Type '%s' undefined",
  93.  aggtransfn1typeName);
  94. xret1 = tup->t_data->t_oid;
  95. fnArgs[0] = xret1;
  96. fnArgs[1] = xbase;
  97. tup = SearchSysCacheTuple(PRONAME,
  98.   PointerGetDatum(aggtransfn1Name),
  99.   Int32GetDatum(2),
  100.   PointerGetDatum(fnArgs),
  101.   0);
  102. if (!HeapTupleIsValid(tup))
  103. elog(ERROR, "AggregateCreate: '%s('%s', '%s') does not exist",
  104.  aggtransfn1Name, aggtransfn1typeName, aggbasetypeName);
  105. if (((Form_pg_proc) GETSTRUCT(tup))->prorettype != xret1)
  106. elog(ERROR, "AggregateCreate: return type of '%s' is not '%s'",
  107.  aggtransfn1Name,
  108.  aggtransfn1typeName);
  109. xfn1 = tup->t_data->t_oid;
  110. if (!OidIsValid(xfn1) || !OidIsValid(xret1) ||
  111. !OidIsValid(xbase))
  112. elog(ERROR, "AggregateCreate: bogus function '%s'", aggfinalfnName);
  113. }
  114. if (aggtransfn2Name)
  115. {
  116. tup = SearchSysCacheTuple(TYPNAME,
  117.   PointerGetDatum(aggtransfn2typeName),
  118.   0, 0, 0);
  119. if (!HeapTupleIsValid(tup))
  120. elog(ERROR, "AggregateCreate: Type '%s' undefined",
  121.  aggtransfn2typeName);
  122. xret2 = tup->t_data->t_oid;
  123. fnArgs[0] = xret2;
  124. fnArgs[1] = 0;
  125. tup = SearchSysCacheTuple(PRONAME,
  126.   PointerGetDatum(aggtransfn2Name),
  127.   Int32GetDatum(1),
  128.   PointerGetDatum(fnArgs),
  129.   0);
  130. if (!HeapTupleIsValid(tup))
  131. elog(ERROR, "AggregateCreate: '%s'('%s') does not exist",
  132.  aggtransfn2Name, aggtransfn2typeName);
  133. if (((Form_pg_proc) GETSTRUCT(tup))->prorettype != xret2)
  134. elog(ERROR, "AggregateCreate: return type of '%s' is not '%s'",
  135.  aggtransfn2Name, aggtransfn2typeName);
  136. xfn2 = tup->t_data->t_oid;
  137. if (!OidIsValid(xfn2) || !OidIsValid(xret2))
  138. elog(ERROR, "AggregateCreate: bogus function '%s'", aggfinalfnName);
  139. }
  140. tup = SearchSysCacheTuple(AGGNAME,
  141.   PointerGetDatum(aggName),
  142.   ObjectIdGetDatum(xbase),
  143.   0, 0);
  144. if (HeapTupleIsValid(tup))
  145. elog(ERROR,
  146.  "AggregateCreate: aggregate '%s' with base type '%s' already exists",
  147.  aggName, aggbasetypeName);
  148. /* more sanity checks */
  149. if (aggtransfn1Name && aggtransfn2Name && !aggfinalfnName)
  150. elog(ERROR, "AggregateCreate: Aggregate must have final function with both transition functions");
  151. if ((!aggtransfn1Name || !aggtransfn2Name) && aggfinalfnName)
  152. elog(ERROR, "AggregateCreate: Aggregate cannot have final function without both transition functions");
  153. if (aggfinalfnName)
  154. {
  155. fnArgs[0] = xret1;
  156. fnArgs[1] = xret2;
  157. tup = SearchSysCacheTuple(PRONAME,
  158.   PointerGetDatum(aggfinalfnName),
  159.   Int32GetDatum(2),
  160.   PointerGetDatum(fnArgs),
  161.   0);
  162. if (!HeapTupleIsValid(tup))
  163. elog(ERROR, "AggregateCreate: '%s'('%s','%s') does not exist",
  164.    aggfinalfnName, aggtransfn1typeName, aggtransfn2typeName);
  165. ffn = tup->t_data->t_oid;
  166. proc = (Form_pg_proc) GETSTRUCT(tup);
  167. fret = proc->prorettype;
  168. if (!OidIsValid(ffn) || !OidIsValid(fret))
  169. elog(ERROR, "AggregateCreate: bogus function '%s'", aggfinalfnName);
  170. }
  171. /*
  172.  * If transition function 2 is defined, it must have an initial value,
  173.  * whereas transition function 1 does not, which allows man and min
  174.  * aggregates to return NULL if they are evaluated on empty sets.
  175.  */
  176. if (OidIsValid(xfn2) && !agginitval2)
  177. elog(ERROR, "AggregateCreate: transition function 2 MUST have an initial value");
  178. /* initialize nulls and values */
  179. for (i = 0; i < Natts_pg_aggregate; i++)
  180. {
  181. nulls[i] = ' ';
  182. values[i] = (Datum) NULL;
  183. }
  184. namestrcpy(&aname, aggName);
  185. values[Anum_pg_aggregate_aggname - 1] = NameGetDatum(&aname);
  186. values[Anum_pg_aggregate_aggowner - 1] = Int32GetDatum(GetUserId());
  187. values[Anum_pg_aggregate_aggtransfn1 - 1] = ObjectIdGetDatum(xfn1);
  188. values[Anum_pg_aggregate_aggtransfn2 - 1] = ObjectIdGetDatum(xfn2);
  189. values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(ffn);
  190. values[Anum_pg_aggregate_aggbasetype - 1] = ObjectIdGetDatum(xbase);
  191. if (!OidIsValid(xfn1))
  192. {
  193. values[Anum_pg_aggregate_aggtranstype1 - 1] = ObjectIdGetDatum(InvalidOid);
  194. values[Anum_pg_aggregate_aggtranstype2 - 1] = ObjectIdGetDatum(xret2);
  195. values[Anum_pg_aggregate_aggfinaltype - 1] = ObjectIdGetDatum(xret2);
  196. }
  197. else if (!OidIsValid(xfn2))
  198. {
  199. values[Anum_pg_aggregate_aggtranstype1 - 1] = ObjectIdGetDatum(xret1);
  200. values[Anum_pg_aggregate_aggtranstype2 - 1] = ObjectIdGetDatum(InvalidOid);
  201. values[Anum_pg_aggregate_aggfinaltype - 1] = ObjectIdGetDatum(xret1);
  202. }
  203. else
  204. {
  205. values[Anum_pg_aggregate_aggtranstype1 - 1] = ObjectIdGetDatum(xret1);
  206. values[Anum_pg_aggregate_aggtranstype2 - 1] = ObjectIdGetDatum(xret2);
  207. values[Anum_pg_aggregate_aggfinaltype - 1] = ObjectIdGetDatum(fret);
  208. }
  209. if (agginitval1)
  210. values[Anum_pg_aggregate_agginitval1 - 1] = PointerGetDatum(textin(agginitval1));
  211. else
  212. nulls[Anum_pg_aggregate_agginitval1 - 1] = 'n';
  213. if (agginitval2)
  214. values[Anum_pg_aggregate_agginitval2 - 1] = PointerGetDatum(textin(agginitval2));
  215. else
  216. nulls[Anum_pg_aggregate_agginitval2 - 1] = 'n';
  217. if (!RelationIsValid(aggdesc = heap_openr(AggregateRelationName)))
  218. elog(ERROR, "AggregateCreate: could not open '%s'",
  219.  AggregateRelationName);
  220. tupDesc = aggdesc->rd_att;
  221. if (!HeapTupleIsValid(tup = heap_formtuple(tupDesc,
  222.    values,
  223.    nulls)))
  224. elog(ERROR, "AggregateCreate: heap_formtuple failed");
  225. if (!OidIsValid(heap_insert(aggdesc, tup)))
  226. elog(ERROR, "AggregateCreate: heap_insert failed");
  227. heap_close(aggdesc);
  228. }
  229. char *
  230. AggNameGetInitVal(char *aggName, Oid basetype, int xfuncno, bool *isNull)
  231. {
  232. HeapTuple tup;
  233. Relation aggRel;
  234. int initValAttno;
  235. Oid transtype;
  236. text    *textInitVal;
  237. char    *strInitVal,
  238.    *initVal;
  239. Assert(PointerIsValid(aggName));
  240. Assert(PointerIsValid(isNull));
  241. Assert(xfuncno == 1 || xfuncno == 2);
  242. tup = SearchSysCacheTuple(AGGNAME,
  243.   PointerGetDatum(aggName),
  244.   ObjectIdGetDatum(basetype),
  245.   0, 0);
  246. if (!HeapTupleIsValid(tup))
  247. elog(ERROR, "AggNameGetInitVal: cache lookup failed for aggregate '%s'",
  248.  aggName);
  249. if (xfuncno == 1)
  250. {
  251. transtype = ((Form_pg_aggregate) GETSTRUCT(tup))->aggtranstype1;
  252. initValAttno = Anum_pg_aggregate_agginitval1;
  253. }
  254. else
  255. /* can only be 1 or 2 */
  256. {
  257. transtype = ((Form_pg_aggregate) GETSTRUCT(tup))->aggtranstype2;
  258. initValAttno = Anum_pg_aggregate_agginitval2;
  259. }
  260. aggRel = heap_openr(AggregateRelationName);
  261. if (!RelationIsValid(aggRel))
  262. elog(ERROR, "AggNameGetInitVal: could not open "%-.*s"",
  263.  AggregateRelationName);
  264. /*
  265.  * must use fastgetattr in case one or other of the init values is
  266.  * NULL
  267.  */
  268. textInitVal = (text *) fastgetattr(tup, initValAttno,
  269.    RelationGetDescr(aggRel),
  270.    isNull);
  271. if (!PointerIsValid(textInitVal))
  272. *isNull = true;
  273. if (*isNull)
  274. {
  275. heap_close(aggRel);
  276. return (char *) NULL;
  277. }
  278. strInitVal = textout(textInitVal);
  279. heap_close(aggRel);
  280. tup = SearchSysCacheTuple(TYPOID,
  281.   ObjectIdGetDatum(transtype),
  282.   0, 0, 0);
  283. if (!HeapTupleIsValid(tup))
  284. {
  285. pfree(strInitVal);
  286. elog(ERROR, "AggNameGetInitVal: cache lookup failed on aggregate transition function return type");
  287. }
  288. initVal = fmgr(((Form_pg_type) GETSTRUCT(tup))->typinput, strInitVal, -1);
  289. pfree(strInitVal);
  290. return initVal;
  291. }