|
6 | 6 | * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group |
7 | 7 | * Portions Copyright (c) 1994, Regents of the University of California |
8 | 8 | * |
9 | | - *$PostgreSQL: pgsql/src/backend/executor/execCurrent.c,v 1.1 2007/06/1101:16:22 tgl Exp $ |
| 9 | + *$PostgreSQL: pgsql/src/backend/executor/execCurrent.c,v 1.2 2007/06/1122:22:40 tgl Exp $ |
10 | 10 | * |
11 | 11 | *------------------------------------------------------------------------- |
12 | 12 | */ |
13 | 13 | #include"postgres.h" |
14 | 14 |
|
| 15 | +#include"catalog/pg_type.h" |
15 | 16 | #include"executor/executor.h" |
| 17 | +#include"utils/builtins.h" |
16 | 18 | #include"utils/lsyscache.h" |
17 | 19 | #include"utils/portal.h" |
18 | 20 |
|
19 | 21 |
|
| 22 | +staticchar*fetch_param_value(ExprContext*econtext,intparamId); |
20 | 23 | staticScanState*search_plan_tree(PlanState*node,Oidtable_oid); |
21 | 24 |
|
22 | 25 |
|
23 | 26 | /* |
24 | 27 | * execCurrentOf |
25 | 28 | * |
26 | | - * Giventhe name of a cursor and the OID of a table, determine which row |
27 | | - * of the table is currently being scanned by the cursor, and return its |
28 | | - * TID into *current_tid. |
| 29 | + * Givena CURRENT OF expression and the OID of a table, determine which row |
| 30 | + * of the table is currently being scanned by the cursor named by CURRENT OF, |
| 31 | + *and return the row'sTID into *current_tid. |
29 | 32 | * |
30 | 33 | * Returns TRUE if a row was identified. Returns FALSE if the cursor is valid |
31 | 34 | * for the table but is not currently scanning a row of the table (this is a |
32 | 35 | * legal situation in inheritance cases). Raises error if cursor is not a |
33 | 36 | * valid updatable scan of the specified table. |
34 | 37 | */ |
35 | 38 | bool |
36 | | -execCurrentOf(char*cursor_name,Oidtable_oid, |
| 39 | +execCurrentOf(CurrentOfExpr*cexpr, |
| 40 | +ExprContext*econtext, |
| 41 | +Oidtable_oid, |
37 | 42 | ItemPointercurrent_tid) |
38 | 43 | { |
| 44 | +char*cursor_name; |
39 | 45 | char*table_name; |
40 | 46 | Portalportal; |
41 | 47 | QueryDesc*queryDesc; |
42 | 48 | ScanState*scanstate; |
43 | | -HeapTupletup; |
| 49 | +boollisnull; |
| 50 | +Oidtuple_tableoid; |
| 51 | +ItemPointertuple_tid; |
| 52 | + |
| 53 | +/* Get the cursor name --- may have to look up a parameter reference */ |
| 54 | +if (cexpr->cursor_name) |
| 55 | +cursor_name=cexpr->cursor_name; |
| 56 | +else |
| 57 | +cursor_name=fetch_param_value(econtext,cexpr->cursor_param); |
44 | 58 |
|
45 | 59 | /* Fetch table name for possible use in error messages */ |
46 | 60 | table_name=get_rel_name(table_oid); |
@@ -100,16 +114,54 @@ execCurrentOf(char *cursor_name, Oid table_oid, |
100 | 114 | if (TupIsNull(scanstate->ss_ScanTupleSlot)) |
101 | 115 | return false; |
102 | 116 |
|
103 | | -tup=scanstate->ss_ScanTupleSlot->tts_tuple; |
104 | | -if (tup==NULL) |
105 | | -elog(ERROR,"CURRENT OF applied to non-materialized tuple"); |
106 | | -Assert(tup->t_tableOid==table_oid); |
| 117 | +/* Use slot_getattr to catch any possible mistakes */ |
| 118 | +tuple_tableoid=DatumGetObjectId(slot_getattr(scanstate->ss_ScanTupleSlot, |
| 119 | +TableOidAttributeNumber, |
| 120 | +&lisnull)); |
| 121 | +Assert(!lisnull); |
| 122 | +tuple_tid= (ItemPointer) |
| 123 | +DatumGetPointer(slot_getattr(scanstate->ss_ScanTupleSlot, |
| 124 | +SelfItemPointerAttributeNumber, |
| 125 | +&lisnull)); |
| 126 | +Assert(!lisnull); |
| 127 | + |
| 128 | +Assert(tuple_tableoid==table_oid); |
107 | 129 |
|
108 | | -*current_tid=tup->t_self; |
| 130 | +*current_tid=*tuple_tid; |
109 | 131 |
|
110 | 132 | return true; |
111 | 133 | } |
112 | 134 |
|
| 135 | +/* |
| 136 | + * fetch_param_value |
| 137 | + * |
| 138 | + * Fetch the string value of a param, verifying it is of type REFCURSOR. |
| 139 | + */ |
| 140 | +staticchar* |
| 141 | +fetch_param_value(ExprContext*econtext,intparamId) |
| 142 | +{ |
| 143 | +ParamListInfoparamInfo=econtext->ecxt_param_list_info; |
| 144 | + |
| 145 | +if (paramInfo&& |
| 146 | +paramId>0&¶mId <=paramInfo->numParams) |
| 147 | +{ |
| 148 | +ParamExternData*prm=¶mInfo->params[paramId-1]; |
| 149 | + |
| 150 | +if (OidIsValid(prm->ptype)&& !prm->isnull) |
| 151 | +{ |
| 152 | +Assert(prm->ptype==REFCURSOROID); |
| 153 | +/* We know that refcursor uses text's I/O routines */ |
| 154 | +returnDatumGetCString(DirectFunctionCall1(textout, |
| 155 | +prm->value)); |
| 156 | +} |
| 157 | +} |
| 158 | + |
| 159 | +ereport(ERROR, |
| 160 | +(errcode(ERRCODE_UNDEFINED_OBJECT), |
| 161 | +errmsg("no value found for parameter %d",paramId))); |
| 162 | +returnNULL; |
| 163 | +} |
| 164 | + |
113 | 165 | /* |
114 | 166 | * search_plan_tree |
115 | 167 | * |
|