Line data Source code
1 : /*------------------------------------------------------------------------- 2 : * 3 : * execJunk.c 4 : * Junk attribute support stuff.... 5 : * 6 : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group 7 : * Portions Copyright (c) 1994, Regents of the University of California 8 : * 9 : * 10 : * IDENTIFICATION 11 : * src/backend/executor/execJunk.c 12 : * 13 : *------------------------------------------------------------------------- 14 : */ 15 : #include "postgres.h" 16 : 17 : #include "executor/executor.h" 18 : 19 : /*------------------------------------------------------------------------- 20 : * XXX this stuff should be rewritten to take advantage 21 : * of ExecProject() and the ProjectionInfo node. 22 : * -cim 6/3/91 23 : * 24 : * An attribute of a tuple living inside the executor, can be 25 : * either a normal attribute or a "junk" attribute. "junk" attributes 26 : * never make it out of the executor, i.e. they are never printed, 27 : * returned or stored on disk. Their only purpose in life is to 28 : * store some information useful only to the executor, mainly the values 29 : * of system attributes like "ctid", or sort key columns that are not to 30 : * be output. 31 : * 32 : * The general idea is the following: A target list consists of a list of 33 : * TargetEntry nodes containing expressions. Each TargetEntry has a field 34 : * called 'resjunk'. If the value of this field is true then the 35 : * corresponding attribute is a "junk" attribute. 36 : * 37 : * When we initialize a plan we call ExecInitJunkFilter to create a filter. 38 : * 39 : * We then execute the plan, treating the resjunk attributes like any others. 40 : * 41 : * Finally, when at the top level we get back a tuple, we can call 42 : * ExecFindJunkAttribute/ExecGetJunkAttribute to retrieve the values of the 43 : * junk attributes we are interested in, and ExecFilterJunk to remove all the 44 : * junk attributes from a tuple. This new "clean" tuple is then printed, 45 : * inserted, or updated. 46 : * 47 : *------------------------------------------------------------------------- 48 : */ 49 : 50 : /* 51 : * ExecInitJunkFilter 52 : * 53 : * Initialize the Junk filter. 54 : * 55 : * The source targetlist is passed in. The output tuple descriptor is 56 : * built from the non-junk tlist entries. 57 : * An optional resultSlot can be passed as well; otherwise, we create one. 58 : */ 59 : JunkFilter * 60 61938 : ExecInitJunkFilter(List *targetList, TupleTableSlot *slot) 61 : { 62 : JunkFilter *junkfilter; 63 : TupleDesc cleanTupType; 64 : int cleanLength; 65 : AttrNumber *cleanMap; 66 : 67 : /* 68 : * Compute the tuple descriptor for the cleaned tuple. 69 : */ 70 61938 : cleanTupType = ExecCleanTypeFromTL(targetList); 71 : 72 : /* 73 : * Use the given slot, or make a new slot if we weren't given one. 74 : */ 75 61938 : if (slot) 76 61938 : ExecSetSlotDescriptor(slot, cleanTupType); 77 : else 78 0 : slot = MakeSingleTupleTableSlot(cleanTupType, &TTSOpsVirtual); 79 : 80 : /* 81 : * Now calculate the mapping between the original tuple's attributes and 82 : * the "clean" tuple's attributes. 83 : * 84 : * The "map" is an array of "cleanLength" attribute numbers, i.e. one 85 : * entry for every attribute of the "clean" tuple. The value of this entry 86 : * is the attribute number of the corresponding attribute of the 87 : * "original" tuple. (Zero indicates a NULL output attribute, but we do 88 : * not use that feature in this routine.) 89 : */ 90 61938 : cleanLength = cleanTupType->natts; 91 61938 : if (cleanLength > 0) 92 : { 93 : AttrNumber cleanResno; 94 : ListCell *t; 95 : 96 61866 : cleanMap = (AttrNumber *) palloc(cleanLength * sizeof(AttrNumber)); 97 61866 : cleanResno = 0; 98 207198 : foreach(t, targetList) 99 : { 100 145332 : TargetEntry *tle = lfirst(t); 101 : 102 145332 : if (!tle->resjunk) 103 : { 104 114766 : cleanMap[cleanResno] = tle->resno; 105 114766 : cleanResno++; 106 : } 107 : } 108 : Assert(cleanResno == cleanLength); 109 : } 110 : else 111 72 : cleanMap = NULL; 112 : 113 : /* 114 : * Finally create and initialize the JunkFilter struct. 115 : */ 116 61938 : junkfilter = makeNode(JunkFilter); 117 : 118 61938 : junkfilter->jf_targetList = targetList; 119 61938 : junkfilter->jf_cleanTupType = cleanTupType; 120 61938 : junkfilter->jf_cleanMap = cleanMap; 121 61938 : junkfilter->jf_resultSlot = slot; 122 : 123 61938 : return junkfilter; 124 : } 125 : 126 : /* 127 : * ExecInitJunkFilterConversion 128 : * 129 : * Initialize a JunkFilter for rowtype conversions. 130 : * 131 : * Here, we are given the target "clean" tuple descriptor rather than 132 : * inferring it from the targetlist. The target descriptor can contain 133 : * deleted columns. It is assumed that the caller has checked that the 134 : * non-deleted columns match up with the non-junk columns of the targetlist. 135 : */ 136 : JunkFilter * 137 1272 : ExecInitJunkFilterConversion(List *targetList, 138 : TupleDesc cleanTupType, 139 : TupleTableSlot *slot) 140 : { 141 : JunkFilter *junkfilter; 142 : int cleanLength; 143 : AttrNumber *cleanMap; 144 : ListCell *t; 145 : int i; 146 : 147 : /* 148 : * Use the given slot, or make a new slot if we weren't given one. 149 : */ 150 1272 : if (slot) 151 1272 : ExecSetSlotDescriptor(slot, cleanTupType); 152 : else 153 0 : slot = MakeSingleTupleTableSlot(cleanTupType, &TTSOpsVirtual); 154 : 155 : /* 156 : * Calculate the mapping between the original tuple's attributes and the 157 : * "clean" tuple's attributes. 158 : * 159 : * The "map" is an array of "cleanLength" attribute numbers, i.e. one 160 : * entry for every attribute of the "clean" tuple. The value of this entry 161 : * is the attribute number of the corresponding attribute of the 162 : * "original" tuple. We store zero for any deleted attributes, marking 163 : * that a NULL is needed in the output tuple. 164 : */ 165 1272 : cleanLength = cleanTupType->natts; 166 1272 : if (cleanLength > 0) 167 : { 168 1272 : cleanMap = (AttrNumber *) palloc0(cleanLength * sizeof(AttrNumber)); 169 1272 : t = list_head(targetList); 170 4600 : for (i = 0; i < cleanLength; i++) 171 : { 172 3328 : if (TupleDescAttr(cleanTupType, i)->attisdropped) 173 66 : continue; /* map entry is already zero */ 174 : for (;;) 175 0 : { 176 3262 : TargetEntry *tle = lfirst(t); 177 : 178 3262 : t = lnext(targetList, t); 179 3262 : if (!tle->resjunk) 180 : { 181 3262 : cleanMap[i] = tle->resno; 182 3262 : break; 183 : } 184 : } 185 : } 186 : } 187 : else 188 0 : cleanMap = NULL; 189 : 190 : /* 191 : * Finally create and initialize the JunkFilter struct. 192 : */ 193 1272 : junkfilter = makeNode(JunkFilter); 194 : 195 1272 : junkfilter->jf_targetList = targetList; 196 1272 : junkfilter->jf_cleanTupType = cleanTupType; 197 1272 : junkfilter->jf_cleanMap = cleanMap; 198 1272 : junkfilter->jf_resultSlot = slot; 199 : 200 1272 : return junkfilter; 201 : } 202 : 203 : /* 204 : * ExecFindJunkAttribute 205 : * 206 : * Locate the specified junk attribute in the junk filter's targetlist, 207 : * and return its resno. Returns InvalidAttrNumber if not found. 208 : */ 209 : AttrNumber 210 0 : ExecFindJunkAttribute(JunkFilter *junkfilter, const char *attrName) 211 : { 212 0 : return ExecFindJunkAttributeInTlist(junkfilter->jf_targetList, attrName); 213 : } 214 : 215 : /* 216 : * ExecFindJunkAttributeInTlist 217 : * 218 : * Find a junk attribute given a subplan's targetlist (not necessarily 219 : * part of a JunkFilter). 220 : */ 221 : AttrNumber 222 161464 : ExecFindJunkAttributeInTlist(List *targetlist, const char *attrName) 223 : { 224 : ListCell *t; 225 : 226 449474 : foreach(t, targetlist) 227 : { 228 332850 : TargetEntry *tle = lfirst(t); 229 : 230 332850 : if (tle->resjunk && tle->resname && 231 83836 : (strcmp(tle->resname, attrName) == 0)) 232 : { 233 : /* We found it ! */ 234 44840 : return tle->resno; 235 : } 236 : } 237 : 238 116624 : return InvalidAttrNumber; 239 : } 240 : 241 : /* 242 : * ExecFilterJunk 243 : * 244 : * Construct and return a slot with all the junk attributes removed. 245 : */ 246 : TupleTableSlot * 247 498884 : ExecFilterJunk(JunkFilter *junkfilter, TupleTableSlot *slot) 248 : { 249 : TupleTableSlot *resultSlot; 250 : AttrNumber *cleanMap; 251 : TupleDesc cleanTupType; 252 : int cleanLength; 253 : int i; 254 : Datum *values; 255 : bool *isnull; 256 : Datum *old_values; 257 : bool *old_isnull; 258 : 259 : /* 260 : * Extract all the values of the old tuple. 261 : */ 262 498884 : slot_getallattrs(slot); 263 498884 : old_values = slot->tts_values; 264 498884 : old_isnull = slot->tts_isnull; 265 : 266 : /* 267 : * get info from the junk filter 268 : */ 269 498884 : cleanTupType = junkfilter->jf_cleanTupType; 270 498884 : cleanLength = cleanTupType->natts; 271 498884 : cleanMap = junkfilter->jf_cleanMap; 272 498884 : resultSlot = junkfilter->jf_resultSlot; 273 : 274 : /* 275 : * Prepare to build a virtual result tuple. 276 : */ 277 498884 : ExecClearTuple(resultSlot); 278 498884 : values = resultSlot->tts_values; 279 498884 : isnull = resultSlot->tts_isnull; 280 : 281 : /* 282 : * Transpose data into proper fields of the new tuple. 283 : */ 284 1546830 : for (i = 0; i < cleanLength; i++) 285 : { 286 1047946 : int j = cleanMap[i]; 287 : 288 1047946 : if (j == 0) 289 : { 290 120 : values[i] = (Datum) 0; 291 120 : isnull[i] = true; 292 : } 293 : else 294 : { 295 1047826 : values[i] = old_values[j - 1]; 296 1047826 : isnull[i] = old_isnull[j - 1]; 297 : } 298 : } 299 : 300 : /* 301 : * And return the virtual tuple. 302 : */ 303 498884 : return ExecStoreVirtualTuple(resultSlot); 304 : }