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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * spi.c
  4.  * Server Programming Interface
  5.  *
  6.  * $Id: spi.c,v 1.39 1999/05/25 22:41:02 momjian Exp $
  7.  *
  8.  *-------------------------------------------------------------------------
  9.  */
  10. #include "executor/spi.h"
  11. #include "executor/spi_priv.h"
  12. #include "catalog/pg_type.h"
  13. #include "access/printtup.h"
  14. #include "fmgr.h"
  15. static Portal _SPI_portal = (Portal) NULL;
  16. static _SPI_connection *_SPI_stack = NULL;
  17. static _SPI_connection *_SPI_current = NULL;
  18. static int _SPI_connected = -1;
  19. static int _SPI_curid = -1;
  20. DLLIMPORT uint32 SPI_processed = 0;
  21. DLLIMPORT SPITupleTable *SPI_tuptable;
  22. DLLIMPORT int SPI_result;
  23. static int _SPI_execute(char *src, int tcount, _SPI_plan *plan);
  24. static int _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount);
  25. static int _SPI_execute_plan(_SPI_plan *plan,
  26.   Datum *Values, char *Nulls, int tcount);
  27. static _SPI_plan *_SPI_copy_plan(_SPI_plan *plan, int location);
  28. static int _SPI_begin_call(bool execmem);
  29. static int _SPI_end_call(bool procmem);
  30. static MemoryContext _SPI_execmem(void);
  31. static MemoryContext _SPI_procmem(void);
  32. static bool _SPI_checktuples(void);
  33. #ifdef SPI_EXECUTOR_STATS
  34. extern int ShowExecutorStats;
  35. extern void ResetUsage(void);
  36. extern void ShowUsage(void);
  37. #endif
  38. /* =================== interface functions =================== */
  39. int
  40. SPI_connect()
  41. {
  42. char pname[64];
  43. PortalVariableMemory pvmem;
  44. /*
  45.  * It's possible on startup and after commit/abort. In future we'll
  46.  * catch commit/abort in some way...
  47.  */
  48. strcpy(pname, "<SPI manager>");
  49. _SPI_portal = GetPortalByName(pname);
  50. if (!PortalIsValid(_SPI_portal))
  51. {
  52. if (_SPI_stack != NULL) /* there was abort */
  53. free(_SPI_stack);
  54. _SPI_current = _SPI_stack = NULL;
  55. _SPI_connected = _SPI_curid = -1;
  56. SPI_processed = 0;
  57. SPI_tuptable = NULL;
  58. _SPI_portal = CreatePortal(pname);
  59. if (!PortalIsValid(_SPI_portal))
  60. elog(FATAL, "SPI_connect: global initialization failed");
  61. }
  62. /*
  63.  * When procedure called by Executor _SPI_curid expected to be equal
  64.  * to _SPI_connected
  65.  */
  66. if (_SPI_curid != _SPI_connected)
  67. return SPI_ERROR_CONNECT;
  68. if (_SPI_stack == NULL)
  69. {
  70. if (_SPI_connected != -1)
  71. elog(FATAL, "SPI_connect: no connection(s) expected");
  72. _SPI_stack = (_SPI_connection *) malloc(sizeof(_SPI_connection));
  73. }
  74. else
  75. {
  76. if (_SPI_connected <= -1)
  77. elog(FATAL, "SPI_connect: some connection(s) expected");
  78. _SPI_stack = (_SPI_connection *) realloc(_SPI_stack,
  79.  (_SPI_connected + 2) * sizeof(_SPI_connection));
  80. }
  81. /*
  82.  * We' returning to procedure where _SPI_curid == _SPI_connected - 1
  83.  */
  84. _SPI_connected++;
  85. _SPI_current = &(_SPI_stack[_SPI_connected]);
  86. _SPI_current->qtlist = NULL;
  87. _SPI_current->processed = 0;
  88. _SPI_current->tuptable = NULL;
  89. /* Create Portal for this procedure ... */
  90. snprintf(pname, 64, "<SPI %d>", _SPI_connected);
  91. _SPI_current->portal = CreatePortal(pname);
  92. if (!PortalIsValid(_SPI_current->portal))
  93. elog(FATAL, "SPI_connect: initialization failed");
  94. /* ... and switch to Portal' Variable memory - procedure' context */
  95. pvmem = PortalGetVariableMemory(_SPI_current->portal);
  96. _SPI_current->savedcxt = MemoryContextSwitchTo((MemoryContext) pvmem);
  97. _SPI_current->savedId = GetScanCommandId();
  98. SetScanCommandId(GetCurrentCommandId());
  99. return SPI_OK_CONNECT;
  100. }
  101. int
  102. SPI_finish()
  103. {
  104. int res;
  105. res = _SPI_begin_call(false); /* live in procedure memory */
  106. if (res < 0)
  107. return res;
  108. /* Restore memory context as it was before procedure call */
  109. MemoryContextSwitchTo(_SPI_current->savedcxt);
  110. PortalDestroy(&(_SPI_current->portal));
  111. SetScanCommandId(_SPI_current->savedId);
  112. /*
  113.  * After _SPI_begin_call _SPI_connected == _SPI_curid. Now we are
  114.  * closing connection to SPI and returning to upper Executor and so
  115.  * _SPI_connected must be equal to _SPI_curid.
  116.  */
  117. _SPI_connected--;
  118. _SPI_curid--;
  119. if (_SPI_connected == -1)
  120. {
  121. free(_SPI_stack);
  122. _SPI_stack = NULL;
  123. }
  124. else
  125. {
  126. _SPI_stack = (_SPI_connection *) realloc(_SPI_stack,
  127.  (_SPI_connected + 1) * sizeof(_SPI_connection));
  128. _SPI_current = &(_SPI_stack[_SPI_connected]);
  129. }
  130. return SPI_OK_FINISH;
  131. }
  132. void
  133. SPI_push(void)
  134. {
  135. _SPI_curid++;
  136. }
  137. void
  138. SPI_pop(void)
  139. {
  140. _SPI_curid--;
  141. }
  142. int
  143. SPI_exec(char *src, int tcount)
  144. {
  145. int res;
  146. if (src == NULL || tcount < 0)
  147. return SPI_ERROR_ARGUMENT;
  148. res = _SPI_begin_call(true);
  149. if (res < 0)
  150. return res;
  151. res = _SPI_execute(src, tcount, NULL);
  152. _SPI_end_call(true);
  153. return res;
  154. }
  155. int
  156. SPI_execp(void *plan, Datum *Values, char *Nulls, int tcount)
  157. {
  158. int res;
  159. if (plan == NULL || tcount < 0)
  160. return SPI_ERROR_ARGUMENT;
  161. if (((_SPI_plan *) plan)->nargs > 0 && Values == NULL)
  162. return SPI_ERROR_PARAM;
  163. res = _SPI_begin_call(true);
  164. if (res < 0)
  165. return res;
  166. /* copy plan to current (executor) context */
  167. plan = (void *) _SPI_copy_plan(plan, _SPI_CPLAN_CURCXT);
  168. res = _SPI_execute_plan((_SPI_plan *) plan, Values, Nulls, tcount);
  169. _SPI_end_call(true);
  170. return res;
  171. }
  172. void *
  173. SPI_prepare(char *src, int nargs, Oid *argtypes)
  174. {
  175. _SPI_plan  *plan;
  176. if (src == NULL || nargs < 0 || (nargs > 0 && argtypes == NULL))
  177. {
  178. SPI_result = SPI_ERROR_ARGUMENT;
  179. return NULL;
  180. }
  181. SPI_result = _SPI_begin_call(true);
  182. if (SPI_result < 0)
  183. return NULL;
  184. plan = (_SPI_plan *) palloc(sizeof(_SPI_plan)); /* Executor context */
  185. plan->argtypes = argtypes;
  186. plan->nargs = nargs;
  187. SPI_result = _SPI_execute(src, 0, plan);
  188. if (SPI_result >= 0) /* copy plan to procedure context */
  189. plan = _SPI_copy_plan(plan, _SPI_CPLAN_PROCXT);
  190. else
  191. plan = NULL;
  192. _SPI_end_call(true);
  193. return (void *) plan;
  194. }
  195. void *
  196. SPI_saveplan(void *plan)
  197. {
  198. _SPI_plan  *newplan;
  199. if (plan == NULL)
  200. {
  201. SPI_result = SPI_ERROR_ARGUMENT;
  202. return NULL;
  203. }
  204. SPI_result = _SPI_begin_call(false); /* don't change context */
  205. if (SPI_result < 0)
  206. return NULL;
  207. newplan = _SPI_copy_plan((_SPI_plan *) plan, _SPI_CPLAN_TOPCXT);
  208. _SPI_curid--;
  209. SPI_result = 0;
  210. return (void *) newplan;
  211. }
  212. HeapTuple
  213. SPI_copytuple(HeapTuple tuple)
  214. {
  215. MemoryContext oldcxt = NULL;
  216. HeapTuple ctuple;
  217. if (tuple == NULL)
  218. {
  219. SPI_result = SPI_ERROR_ARGUMENT;
  220. return NULL;
  221. }
  222. if (_SPI_curid + 1 == _SPI_connected) /* connected */
  223. {
  224. if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
  225. elog(FATAL, "SPI: stack corrupted");
  226. oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
  227. }
  228. ctuple = heap_copytuple(tuple);
  229. if (oldcxt)
  230. MemoryContextSwitchTo(oldcxt);
  231. return ctuple;
  232. }
  233. HeapTuple
  234. SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum,
  235. Datum *Values, char *Nulls)
  236. {
  237. MemoryContext oldcxt = NULL;
  238. HeapTuple mtuple;
  239. int numberOfAttributes;
  240. uint8 infomask;
  241. Datum    *v;
  242. char    *n;
  243. bool isnull;
  244. int i;
  245. if (rel == NULL || tuple == NULL || natts <= 0 || attnum == NULL || Values == NULL)
  246. {
  247. SPI_result = SPI_ERROR_ARGUMENT;
  248. return NULL;
  249. }
  250. if (_SPI_curid + 1 == _SPI_connected) /* connected */
  251. {
  252. if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
  253. elog(FATAL, "SPI: stack corrupted");
  254. oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
  255. }
  256. SPI_result = 0;
  257. numberOfAttributes = rel->rd_att->natts;
  258. v = (Datum *) palloc(numberOfAttributes * sizeof(Datum));
  259. n = (char *) palloc(numberOfAttributes * sizeof(char));
  260. /* fetch old values and nulls */
  261. for (i = 0; i < numberOfAttributes; i++)
  262. {
  263. v[i] = heap_getattr(tuple, i + 1, rel->rd_att, &isnull);
  264. n[i] = (isnull) ? 'n' : ' ';
  265. }
  266. /* replace values and nulls */
  267. for (i = 0; i < natts; i++)
  268. {
  269. if (attnum[i] <= 0 || attnum[i] > numberOfAttributes)
  270. break;
  271. v[attnum[i] - 1] = Values[i];
  272. n[attnum[i] - 1] = (Nulls && Nulls[i] == 'n') ? 'n' : ' ';
  273. }
  274. if (i == natts) /* no errors in *attnum */
  275. {
  276. mtuple = heap_formtuple(rel->rd_att, v, n);
  277. infomask = mtuple->t_data->t_infomask;
  278. memmove(&(mtuple->t_data->t_oid), &(tuple->t_data->t_oid),
  279. ((char *) &(tuple->t_data->t_hoff) -
  280.  (char *) &(tuple->t_data->t_oid)));
  281. mtuple->t_data->t_infomask = infomask;
  282. mtuple->t_data->t_natts = numberOfAttributes;
  283. }
  284. else
  285. {
  286. mtuple = NULL;
  287. SPI_result = SPI_ERROR_NOATTRIBUTE;
  288. }
  289. pfree(v);
  290. pfree(n);
  291. if (oldcxt)
  292. MemoryContextSwitchTo(oldcxt);
  293. return mtuple;
  294. }
  295. int
  296. SPI_fnumber(TupleDesc tupdesc, char *fname)
  297. {
  298. int res;
  299. for (res = 0; res < tupdesc->natts; res++)
  300. {
  301. if (strcasecmp(tupdesc->attrs[res]->attname.data, fname) == 0)
  302. return res + 1;
  303. }
  304. return SPI_ERROR_NOATTRIBUTE;
  305. }
  306. char *
  307. SPI_fname(TupleDesc tupdesc, int fnumber)
  308. {
  309. SPI_result = 0;
  310. if (tupdesc->natts < fnumber || fnumber <= 0)
  311. {
  312. SPI_result = SPI_ERROR_NOATTRIBUTE;
  313. return NULL;
  314. }
  315. return nameout(&(tupdesc->attrs[fnumber - 1]->attname));
  316. }
  317. char *
  318. SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
  319. {
  320. Datum val;
  321. bool isnull;
  322. Oid foutoid,
  323. typelem;
  324. SPI_result = 0;
  325. if (tuple->t_data->t_natts < fnumber || fnumber <= 0)
  326. {
  327. SPI_result = SPI_ERROR_NOATTRIBUTE;
  328. return NULL;
  329. }
  330. val = heap_getattr(tuple, fnumber, tupdesc, &isnull);
  331. if (isnull)
  332. return NULL;
  333. if (!getTypeOutAndElem((Oid) tupdesc->attrs[fnumber - 1]->atttypid,
  334.    &foutoid, &typelem))
  335. {
  336. SPI_result = SPI_ERROR_NOOUTFUNC;
  337. return NULL;
  338. }
  339. return (fmgr(foutoid, val, typelem,
  340.  tupdesc->attrs[fnumber - 1]->atttypmod));
  341. }
  342. Datum
  343. SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
  344. {
  345. Datum val;
  346. *isnull = true;
  347. SPI_result = 0;
  348. if (tuple->t_data->t_natts < fnumber || fnumber <= 0)
  349. {
  350. SPI_result = SPI_ERROR_NOATTRIBUTE;
  351. return (Datum) NULL;
  352. }
  353. val = heap_getattr(tuple, fnumber, tupdesc, isnull);
  354. return val;
  355. }
  356. char *
  357. SPI_gettype(TupleDesc tupdesc, int fnumber)
  358. {
  359. HeapTuple typeTuple;
  360. SPI_result = 0;
  361. if (tupdesc->natts < fnumber || fnumber <= 0)
  362. {
  363. SPI_result = SPI_ERROR_NOATTRIBUTE;
  364. return NULL;
  365. }
  366. typeTuple = SearchSysCacheTuple(TYPOID,
  367.  ObjectIdGetDatum(tupdesc->attrs[fnumber - 1]->atttypid),
  368. 0, 0, 0);
  369. if (!HeapTupleIsValid(typeTuple))
  370. {
  371. SPI_result = SPI_ERROR_TYPUNKNOWN;
  372. return NULL;
  373. }
  374. return pstrdup(((Form_pg_type) GETSTRUCT(typeTuple))->typname.data);
  375. }
  376. Oid
  377. SPI_gettypeid(TupleDesc tupdesc, int fnumber)
  378. {
  379. SPI_result = 0;
  380. if (tupdesc->natts < fnumber || fnumber <= 0)
  381. {
  382. SPI_result = SPI_ERROR_NOATTRIBUTE;
  383. return InvalidOid;
  384. }
  385. return tupdesc->attrs[fnumber - 1]->atttypid;
  386. }
  387. char *
  388. SPI_getrelname(Relation rel)
  389. {
  390. return pstrdup(rel->rd_rel->relname.data);
  391. }
  392. void *
  393. SPI_palloc(Size size)
  394. {
  395. MemoryContext oldcxt = NULL;
  396. void    *pointer;
  397. if (_SPI_curid + 1 == _SPI_connected) /* connected */
  398. {
  399. if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
  400. elog(FATAL, "SPI: stack corrupted");
  401. oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
  402. }
  403. pointer = palloc(size);
  404. if (oldcxt)
  405. MemoryContextSwitchTo(oldcxt);
  406. return pointer;
  407. }
  408. void *
  409. SPI_repalloc(void *pointer, Size size)
  410. {
  411. MemoryContext oldcxt = NULL;
  412. if (_SPI_curid + 1 == _SPI_connected) /* connected */
  413. {
  414. if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
  415. elog(FATAL, "SPI: stack corrupted");
  416. oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
  417. }
  418. pointer = repalloc(pointer, size);
  419. if (oldcxt)
  420. MemoryContextSwitchTo(oldcxt);
  421. return pointer;
  422. }
  423. void
  424. SPI_pfree(void *pointer)
  425. {
  426. MemoryContext oldcxt = NULL;
  427. if (_SPI_curid + 1 == _SPI_connected) /* connected */
  428. {
  429. if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
  430. elog(FATAL, "SPI: stack corrupted");
  431. oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
  432. }
  433. pfree(pointer);
  434. if (oldcxt)
  435. MemoryContextSwitchTo(oldcxt);
  436. return;
  437. }
  438. /* =================== private functions =================== */
  439. /*
  440.  * spi_printtup
  441.  * store tuple retrieved by Executor into SPITupleTable
  442.  * of current SPI procedure
  443.  *
  444.  */
  445. void
  446. spi_printtup(HeapTuple tuple, TupleDesc tupdesc, DestReceiver *self)
  447. {
  448. SPITupleTable *tuptable;
  449. MemoryContext oldcxt;
  450. /*
  451.  * When called by Executor _SPI_curid expected to be equal to
  452.  * _SPI_connected
  453.  */
  454. if (_SPI_curid != _SPI_connected || _SPI_connected < 0)
  455. elog(FATAL, "SPI: improper call to spi_printtup");
  456. if (_SPI_current != &(_SPI_stack[_SPI_curid]))
  457. elog(FATAL, "SPI: stack corrupted in spi_printtup");
  458. oldcxt = _SPI_procmem(); /* switch to procedure memory context */
  459. tuptable = _SPI_current->tuptable;
  460. if (tuptable == NULL)
  461. {
  462. _SPI_current->tuptable = tuptable = (SPITupleTable *)
  463. palloc(sizeof(SPITupleTable));
  464. tuptable->alloced = tuptable->free = 128;
  465. tuptable->vals = (HeapTuple *) palloc(tuptable->alloced * sizeof(HeapTuple));
  466. tuptable->tupdesc = CreateTupleDescCopy(tupdesc);
  467. }
  468. else if (tuptable->free == 0)
  469. {
  470. tuptable->free = 256;
  471. tuptable->alloced += tuptable->free;
  472. tuptable->vals = (HeapTuple *) repalloc(tuptable->vals,
  473.   tuptable->alloced * sizeof(HeapTuple));
  474. }
  475. tuptable->vals[tuptable->alloced - tuptable->free] = heap_copytuple(tuple);
  476. (tuptable->free)--;
  477. MemoryContextSwitchTo(oldcxt);
  478. return;
  479. }
  480. /*
  481.  * Static functions
  482.  */
  483. static int
  484. _SPI_execute(char *src, int tcount, _SPI_plan *plan)
  485. {
  486. List    *queryTree_list;
  487. List    *planTree_list;
  488. List    *queryTree_list_item;
  489. List    *ptlist;
  490. QueryDesc  *qdesc;
  491. Query    *queryTree;
  492. Plan    *planTree;
  493. EState    *state;
  494. int nargs = 0;
  495. Oid    *argtypes = NULL;
  496. int res = 0;
  497. bool islastquery;
  498. /* Increment CommandCounter to see changes made by now */
  499. CommandCounterIncrement();
  500. SPI_processed = 0;
  501. SPI_tuptable = NULL;
  502. _SPI_current->tuptable = NULL;
  503. _SPI_current->qtlist = NULL;
  504. if (plan)
  505. {
  506. nargs = plan->nargs;
  507. argtypes = plan->argtypes;
  508. }
  509. ptlist = planTree_list =
  510. pg_parse_and_plan(src, argtypes, nargs, &queryTree_list, None, FALSE);
  511. _SPI_current->qtlist = queryTree_list;
  512. foreach(queryTree_list_item, queryTree_list)
  513. {
  514. queryTree = (Query *) lfirst(queryTree_list_item);
  515. planTree = lfirst(planTree_list);
  516. planTree_list = lnext(planTree_list);
  517. islastquery = (planTree_list == NIL); /* assume lists are same
  518.  * len */
  519. if (queryTree->commandType == CMD_UTILITY)
  520. {
  521. if (nodeTag(queryTree->utilityStmt) == T_CopyStmt)
  522. {
  523. CopyStmt   *stmt = (CopyStmt *) (queryTree->utilityStmt);
  524. if (stmt->filename == NULL)
  525. return SPI_ERROR_COPY;
  526. }
  527. else if (nodeTag(queryTree->utilityStmt) == T_ClosePortalStmt ||
  528.  nodeTag(queryTree->utilityStmt) == T_FetchStmt)
  529. return SPI_ERROR_CURSOR;
  530. else if (nodeTag(queryTree->utilityStmt) == T_TransactionStmt)
  531. return SPI_ERROR_TRANSACTION;
  532. res = SPI_OK_UTILITY;
  533. if (plan == NULL)
  534. {
  535. ProcessUtility(queryTree->utilityStmt, None);
  536. if (!islastquery)
  537. CommandCounterIncrement();
  538. else
  539. return res;
  540. }
  541. else if (islastquery)
  542. break;
  543. }
  544. else if (plan == NULL)
  545. {
  546. qdesc = CreateQueryDesc(queryTree, planTree,
  547. islastquery ? SPI : None);
  548. state = CreateExecutorState();
  549. res = _SPI_pquery(qdesc, state, islastquery ? tcount : 0);
  550. if (res < 0 || islastquery)
  551. return res;
  552. CommandCounterIncrement();
  553. }
  554. else
  555. {
  556. qdesc = CreateQueryDesc(queryTree, planTree,
  557. islastquery ? SPI : None);
  558. res = _SPI_pquery(qdesc, NULL, islastquery ? tcount : 0);
  559. if (res < 0)
  560. return res;
  561. if (islastquery)
  562. break;
  563. }
  564. }
  565. plan->qtlist = queryTree_list;
  566. plan->ptlist = ptlist;
  567. return res;
  568. }
  569. static int
  570. _SPI_execute_plan(_SPI_plan *plan, Datum *Values, char *Nulls, int tcount)
  571. {
  572. List    *queryTree_list = plan->qtlist;
  573. List    *planTree_list = plan->ptlist;
  574. List    *queryTree_list_item;
  575. QueryDesc  *qdesc;
  576. Query    *queryTree;
  577. Plan    *planTree;
  578. EState    *state;
  579. int nargs = plan->nargs;
  580. int res = 0;
  581. bool islastquery;
  582. int k;
  583. /* Increment CommandCounter to see changes made by now */
  584. CommandCounterIncrement();
  585. SPI_processed = 0;
  586. SPI_tuptable = NULL;
  587. _SPI_current->tuptable = NULL;
  588. _SPI_current->qtlist = NULL;
  589. foreach(queryTree_list_item, queryTree_list)
  590. {
  591. queryTree = (Query *) lfirst(queryTree_list_item);
  592. planTree = lfirst(planTree_list);
  593. planTree_list = lnext(planTree_list);
  594. islastquery = (planTree_list == NIL); /* assume lists are same
  595.  * len */
  596. if (queryTree->commandType == CMD_UTILITY)
  597. {
  598. ProcessUtility(queryTree->utilityStmt, None);
  599. if (!islastquery)
  600. CommandCounterIncrement();
  601. else
  602. return SPI_OK_UTILITY;
  603. }
  604. else
  605. {
  606. qdesc = CreateQueryDesc(queryTree, planTree,
  607. islastquery ? SPI : None);
  608. state = CreateExecutorState();
  609. if (nargs > 0)
  610. {
  611. ParamListInfo paramLI = (ParamListInfo) palloc((nargs + 1) *
  612.   sizeof(ParamListInfoData));
  613. state->es_param_list_info = paramLI;
  614. for (k = 0; k < plan->nargs; paramLI++, k++)
  615. {
  616. paramLI->kind = PARAM_NUM;
  617. paramLI->id = k + 1;
  618. paramLI->isnull = (Nulls && Nulls[k] == 'n');
  619. paramLI->value = Values[k];
  620. }
  621. paramLI->kind = PARAM_INVALID;
  622. }
  623. else
  624. state->es_param_list_info = NULL;
  625. res = _SPI_pquery(qdesc, state, islastquery ? tcount : 0);
  626. if (res < 0 || islastquery)
  627. return res;
  628. CommandCounterIncrement();
  629. }
  630. }
  631. return res;
  632. }
  633. static int
  634. _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
  635. {
  636. Query    *parseTree = queryDesc->parsetree;
  637. Plan    *plan = queryDesc->plantree;
  638. int operation = queryDesc->operation;
  639. CommandDest dest = queryDesc->dest;
  640. TupleDesc tupdesc;
  641. bool isRetrieveIntoPortal = false;
  642. bool isRetrieveIntoRelation = false;
  643. char    *intoName = NULL;
  644. int res;
  645. Const tcount_const;
  646. Node    *count = NULL;
  647. switch (operation)
  648. {
  649. case CMD_SELECT:
  650. res = SPI_OK_SELECT;
  651. if (parseTree->isPortal)
  652. {
  653. isRetrieveIntoPortal = true;
  654. intoName = parseTree->into;
  655. parseTree->isBinary = false; /* */
  656. return SPI_ERROR_CURSOR;
  657. }
  658. else if (parseTree->into != NULL) /* select into table */
  659. {
  660. res = SPI_OK_SELINTO;
  661. isRetrieveIntoRelation = true;
  662. queryDesc->dest = None; /* */
  663. }
  664. break;
  665. case CMD_INSERT:
  666. res = SPI_OK_INSERT;
  667. break;
  668. case CMD_DELETE:
  669. res = SPI_OK_DELETE;
  670. break;
  671. case CMD_UPDATE:
  672. res = SPI_OK_UPDATE;
  673. break;
  674. default:
  675. return SPI_ERROR_OPUNKNOWN;
  676. }
  677. /* ----------------
  678.  * Get the query LIMIT tuple count
  679.  * ----------------
  680.  */
  681. if (parseTree->limitCount != NULL)
  682. {
  683. /* ----------------
  684.  * A limit clause in the parsetree overrides the
  685.  * tcount parameter
  686.  * ----------------
  687.  */
  688. count = parseTree->limitCount;
  689. }
  690. else
  691. {
  692. /* ----------------
  693.  * No LIMIT clause in parsetree. Use a local Const node
  694.  * to put tcount into it
  695.  * ----------------
  696.  */
  697. memset(&tcount_const, 0, sizeof(tcount_const));
  698. tcount_const.type = T_Const;
  699. tcount_const.consttype = INT4OID;
  700. tcount_const.constlen = sizeof(int4);
  701. tcount_const.constvalue = (Datum) tcount;
  702. tcount_const.constisnull = FALSE;
  703. tcount_const.constbyval = TRUE;
  704. tcount_const.constisset = FALSE;
  705. tcount_const.constiscast = FALSE;
  706. count = (Node *) &tcount_const;
  707. }
  708. if (state == NULL) /* plan preparation */
  709. return res;
  710. #ifdef SPI_EXECUTOR_STATS
  711. if (ShowExecutorStats)
  712. ResetUsage();
  713. #endif
  714. tupdesc = ExecutorStart(queryDesc, state);
  715. /* Don't work currently */
  716. if (isRetrieveIntoPortal)
  717. {
  718. ProcessPortal(intoName,
  719.   parseTree,
  720.   plan,
  721.   state,
  722.   tupdesc,
  723.   None);
  724. return SPI_OK_CURSOR;
  725. }
  726. ExecutorRun(queryDesc, state, EXEC_FOR, parseTree->limitOffset, count);
  727. _SPI_current->processed = state->es_processed;
  728. if (operation == CMD_SELECT && queryDesc->dest == SPI)
  729. {
  730. if (_SPI_checktuples())
  731. elog(FATAL, "SPI_select: # of processed tuples check failed");
  732. }
  733. ExecutorEnd(queryDesc, state);
  734. #ifdef SPI_EXECUTOR_STATS
  735. if (ShowExecutorStats)
  736. {
  737. fprintf(stderr, "! Executor Stats:n");
  738. ShowUsage();
  739. }
  740. #endif
  741. if (dest == SPI)
  742. {
  743. SPI_processed = _SPI_current->processed;
  744. SPI_tuptable = _SPI_current->tuptable;
  745. }
  746. queryDesc->dest = dest;
  747. return res;
  748. }
  749. static MemoryContext
  750. _SPI_execmem()
  751. {
  752. MemoryContext oldcxt;
  753. PortalHeapMemory phmem;
  754. phmem = PortalGetHeapMemory(_SPI_current->portal);
  755. oldcxt = MemoryContextSwitchTo((MemoryContext) phmem);
  756. return oldcxt;
  757. }
  758. static MemoryContext
  759. _SPI_procmem()
  760. {
  761. MemoryContext oldcxt;
  762. PortalVariableMemory pvmem;
  763. pvmem = PortalGetVariableMemory(_SPI_current->portal);
  764. oldcxt = MemoryContextSwitchTo((MemoryContext) pvmem);
  765. return oldcxt;
  766. }
  767. /*
  768.  * _SPI_begin_call
  769.  *
  770.  */
  771. static int
  772. _SPI_begin_call(bool execmem)
  773. {
  774. if (_SPI_curid + 1 != _SPI_connected)
  775. return SPI_ERROR_UNCONNECTED;
  776. _SPI_curid++;
  777. if (_SPI_current != &(_SPI_stack[_SPI_curid]))
  778. elog(FATAL, "SPI: stack corrupted");
  779. if (execmem) /* switch to the Executor memory context */
  780. {
  781. _SPI_execmem();
  782. StartPortalAllocMode(DefaultAllocMode, 0);
  783. }
  784. return 0;
  785. }
  786. static int
  787. _SPI_end_call(bool procmem)
  788. {
  789. /*
  790.  * We' returning to procedure where _SPI_curid == _SPI_connected - 1
  791.  */
  792. _SPI_curid--;
  793. _SPI_current->qtlist = NULL;
  794. if (procmem) /* switch to the procedure memory context */
  795. { /* but free Executor memory before */
  796. EndPortalAllocMode();
  797. _SPI_procmem();
  798. }
  799. return 0;
  800. }
  801. static bool
  802. _SPI_checktuples()
  803. {
  804. uint32 processed = _SPI_current->processed;
  805. SPITupleTable *tuptable = _SPI_current->tuptable;
  806. bool failed = false;
  807. if (processed == 0)
  808. {
  809. if (tuptable != NULL)
  810. failed = true;
  811. }
  812. else
  813. /* some tuples were processed */
  814. {
  815. if (tuptable == NULL) /* spi_printtup was not called */
  816. failed = true;
  817. else if (processed != (tuptable->alloced - tuptable->free))
  818. failed = true;
  819. }
  820. return failed;
  821. }
  822. static _SPI_plan *
  823. _SPI_copy_plan(_SPI_plan *plan, int location)
  824. {
  825. _SPI_plan  *newplan;
  826. MemoryContext oldcxt = NULL;
  827. if (location == _SPI_CPLAN_PROCXT)
  828. oldcxt = MemoryContextSwitchTo((MemoryContext)
  829.   PortalGetVariableMemory(_SPI_current->portal));
  830. else if (location == _SPI_CPLAN_TOPCXT)
  831. oldcxt = MemoryContextSwitchTo(TopMemoryContext);
  832. newplan = (_SPI_plan *) palloc(sizeof(_SPI_plan));
  833. newplan->qtlist = (List *) copyObject(plan->qtlist);
  834. newplan->ptlist = (List *) copyObject(plan->ptlist);
  835. newplan->nargs = plan->nargs;
  836. if (plan->nargs > 0)
  837. {
  838. newplan->argtypes = (Oid *) palloc(plan->nargs * sizeof(Oid));
  839. memcpy(newplan->argtypes, plan->argtypes, plan->nargs * sizeof(Oid));
  840. }
  841. else
  842. newplan->argtypes = NULL;
  843. if (location != _SPI_CPLAN_CURCXT)
  844. MemoryContextSwitchTo(oldcxt);
  845. return newplan;
  846. }