What is the implementation method of getting tuple attribute values when PostgreSQL executes a query?
Attcacheoff > = 0) off = thisatt- > attcacheoff; else if (thisatt- > attlen = =-1) {/ * We can only cache the offset for a varlena attribute if the * offset is already suitably aligned, so that there would be no * pad bytes in any case: then the offset will be valid for either * an aligned or unaligned value. * varlena: offset is valid whether it is aligned or not. * / if (! slow & & off = = att_align_nominal (off, thisatt- > attalign)) thisatt- > attcacheoff = off; else {off = att_align_pointer (off, thisatt- > attalign,-1, tp + off); slow = true }} else {/ * not varlena, so safe to use att_align_nominal * / / non-varlena: use att_align_nominal off = att_align_nominal (off, thisatt- > attalign); if (! slow) thisatt- > attcacheoff = off } / / get column values values [attnum] = fetchatt (thisatt, tp + off); / / adjust offset off = att_addlength_pointer (off, thisatt- > attlen, tp + off); if (thisatt- > attlen attrs [(I)]) # define fetchatt (A) fetch_att (T, (A)-> attbyval, (A)-> attlen) / * * Same, but work from byval/len parameters rather than Form_pg_attribute. * / # if SIZEOF_DATUM = = 8#define fetch_att (TMagne attbyval Attlen)\ (attbyval)?\ (attlen) = = (int) sizeof (Datum)?\ * ((Datum *) (T))\: (\ (attlen) = = (int) sizeof (int32)?\ Int32GetDatum (* ((int32 *) (T)\:\ (\ (attlen) = (int) sizeof (int16)?\ Int16GetDatum (* ((int16 *) (T)\:\ (\ AssertMacro ((attlen) = = 1) \ CharGetDatum (* ((char *) (T)\)\:\ PointerGetDatum ((char *) (T))\) # else / * SIZEOF_DATUM! = 8 * / # define fetch_att Attlen)\ (attbyval)?\ (attlen) = = (int) sizeof (int32)?\ Int32GetDatum (* ((int32 *) (T)\:\ (attlen) = = (int) sizeof (int16)?\ Int16GetDatum (* ((int16 *) (T)\ :\ (\ AssertMacro ((attlen) = = 1) \ CharGetDatum (* (char *) (T))\)\:\ PointerGetDatum ((char *) (T))\) # endif / * SIZEOF_DATUM = = 8 * / * * DatumGetPointer * Returns pointer value of a datum. * / # define DatumGetPointer (X) ((Pointer) (X)) / * PointerGetDatum * Returns datum representation for a pointer. * / # define PointerGetDatum (X) ((Datum) (X)) III. Tracking analysis
Perform SQL:
[local]: 5432 pg12@testdb=# select * from t_getattrs
Start gdb and enter the breakpoint
(gdb) b slot_deform_heap_tupleBreakpoint 3 at 0x6fdeac: file execTuples.c, line 892. (gdb) cContinuing.Breakpoint 3, slot_deform_heap_tuple (slot=0x12312a0, tuple=0x1231880, offp=0x12312e8, natts=5) at execTuples.c:892892 TupleDesc tupleDesc = slot- > tts_tupleDescriptor (gdb) bt#0 slot_deform_heap_tuple (slot=0x12312a0, tuple=0x1231880, offp=0x12312e8, natts=5) at execTuples.c:892#1 0x00000000006fd7d6 in tts_buffer_heap_getsomeattrs (slot=0x12312a0, natts=5) at execTuples.c:676#2 0x00000000006ff7a9 in slot_getsomeattrs_int (slot=0x12312a0, attnum=5) at execTuples.c:1877#3 0x000000000048ed13 in slot_getsomeattrs (slot=0x12312a0 Attnum=5) at. / src/include/executor/tuptable.h:345#4 0x000000000048ed39 in slot_getallattrs (slot=0x12312a0) at. / src/include/executor/tuptable.h:357#5 0x000000000048f88a in printtup (slot=0x12312a0, self=0x1239a50) at printtup.c:392#6 0x00000000006efc3c in ExecutePlan (estate=0x1230e38, planstate=0x1231090, use_parallel_mode=false, operation=CMD_SELECT, sendTuples=true, numberTuples=0, direction=ForwardScanDirection, dest=0x1239a50, execute_once=true) at execMain.c:1685#7 0x00000000006ed9df in standard_ExecutorRun (queryDesc=0x121b978, direction=ForwardScanDirection) Count=0, execute_once=true) at execMain.c:364#8 0x00000000006ed815 in ExecutorRun (queryDesc=0x121b978, direction=ForwardScanDirection, count=0, execute_once=true) at execMain.c:308#9 0x00000000008f1010 in PortalRunSelect (portal=0x11b9c08, forward=true, count=0, dest=0x1239a50) at pquery.c:929#10 0x00000000008f0cae in PortalRun (portal=0x11b9c08, count=9223372036854775807, isTopLevel=true, run_once=true, dest=0x1239a50, altdest=0x1239a50, completionTag=0x7ffd32962250 ") at pquery.c:770#11 0x00000000008ead35 in exec_simple_query (query_string=0x1152d98" select * from t_getattrs ") At postgres.c:1215#12 0x00000000008eefa5 in PostgresMain (argc=1, argv=0x117fda8, dbname=0x117fbf0 "testdb", username=0x114fab8 "pg12") at postgres.c:4236#13 0x0000000000845915 in BackendRun (port=0x1175bc0) at postmaster.c:4431#14 0x00000000008450f3 in BackendStartup (port=0x1175bc0) at postmaster.c:4122---Type to continue, or q to quit---#15 0x000000000084132f in ServerLoop () at postmaster.c:1704#16 0x0000000000840be5 in PostmasterMain (argc=1, argv=0x114da70) at postmaster.c:1377#17 0x0000000000761469 in main (argc=1, argv=0x114da70) at main.c:228 (gdb) (gdb)
Input parameters
(gdb) p * slot-- > tuple slot$1 = {type = T_TupleTableSlot, tts_flags = 16, tts_nvalid = 0, tts_ops = 0xc3e780, tts_tupleDescriptor = 0x7fe1af2fd7a8, tts_values = 0x1231310, tts_isnull = 0x1231338, tts_mcxt = 0x1230d20, tts_tid = {ip_blkid = {bi_hi = 0, bi_lo = 0}, ip_posid = 1}, tts_tableOid = 131110} (gdb) p tuple$2 = (HeapTuple) 0x1231880 (gdb) p * tuple-> tuple $3 = {t_len = 67 T_self = {ip_blkid = {bi_hi = 0, bi_lo = 0}, ip_posid = 1}, t_tableOid = 131110, t_data = 0x7fe18396e438} (gdb) p * offp-> offset $4 = 0 (gdb) p natts-> 5 attributes $5 = 5 (gdb)
Initialize related variables
(gdb) n893 Datum * values = slot- > tts_values; (gdb) 894 bool * isnull = slot- > tts_isnull; (gdb) 895 HeapTupleHeader tup = tuple- > Twitter data; (gdb) p * values$6 = 0 (gdb) p * isnull$7 = false (gdb) n896 bool hasnulls = HeapTupleHasNulls (tuple); (gdb) 900bits8 * bp = tup- > t_bits / * ptr to null bitmap in tuple * / (gdb) 904 natts = Min (HeapTupleHeaderGetNatts (tuple- > t_data), natts); (gdb) p * bp$8 = 0'\ 000' (gdb) n910 attnum = slot- > tts_nvalid; (gdb) p natts$9 = 5 (gdb) n911 if (attnum = = 0) (gdb) p attnum$10 = 0 (gdb)
Execute for the first time, set offset and other information, and initialize tuple data pointer
(gdb) n914 off = 0; (gdb) 915 slow = false; (gdb) 924 tp = (char *) tup + tup- > t_hoff (gdb) p tup- > t_hoff$11 = 24'\ 030' (gdb) p * tup--> Tuple header information $12 = {t_choice = {t_heap = {t_xmin = 14764, t_xmax = 0, t_field3 = {t_cid = 0, t_xvac = 0}}, t_datum = {datum_len_ = 14764, datum_typmod = 0, datum_typeid = 0}}, t_ctid = {ip_blkid = {bi_hi = 0, bi_lo = 0} Ip_posid = 1}, t_infomask2 = 5, t_infomask = 2306, t_hoff = 24'\ 030mm, t_bits = 0x7fe18396e44f ""} (gdb)
Start a loop to get the value of each property
(gdb) n926 for (; attnum
< natts; attnum++)(gdb) 928 Form_pg_attribute thisatt = TupleDescAttr(tupleDesc, attnum);(gdb) 930 if (hasnulls && att_isnull(attnum, bp)) 属性信息 (gdb) p thisatt$13 = (Form_pg_attribute) 0x7fe1af2fd7c0(gdb) p *thisatt$14 = {attrelid = 131110, attname = {data = "id", '\000' }, atttypid = 23, attstattarget = -1, attlen = 4, attnum = 1, attndims = 0, attcacheoff = 0, atttypmod = -1, attbyval = true, attstorage = 112 'p', attalign = 105 'i', attnotnull = false, atthasdef = false, atthasmissing = false, attidentity = 0 '\000', attgenerated = 0 '\000', attisdropped = false, attislocal = true, attinhcount = 0, attcollation = 0}(gdb) 获取第1个属性值,即id的值。注意:fetchatt执行的逻辑是Int32GetDatum(*((int32 *)(T))) (gdb) p thisatt->Attbyval$18 = true (gdb) p thisatt- > attlen$19 = 4 (gdb) p SIZEOF_DATUM$24 = 8 (gdb) p (int) sizeof (Datum) $26 = 8 (gdb) p (int) sizeof (int32) $27 = 4 (gdb) (gdb) p Int32GetDatum (* (int32 *) (tp+off)) $25 = (int) sizeof (int32)?\ Int32GetDatum (* (int32 *) (T)\ #
Gets the second property value, the value of col_varchar. Note: the logic executed by fetchatt is PointerGetDatum ((char *) (T)
(gdb) n973 if (thisatt- > attlen attcacheoff > = 0) (gdb) 941 off = thisatt- > attcacheoff; (gdb) 969 values [attnum] = fetchatt (thisatt, tp + off) (gdb) p off$29 = 4 (gdb) p PointerGetDatum ((char *) (tp+off)) $30 = 140606552073300 (gdb) x tp+off 5c PointerGetDatum ((char *) (tp+off)) 0x7fe18396e454: 11'\ v '116' t '101' e '115' (gdb) p (char *) PointerGetDatum ((char *) (tp+off)) $32 = 0x7fe18396e454 "\ vtest\ 027test" (gdb)
Gets the second property value, the value of col_char. Note: the logic executed by fetchatt is PointerGetDatum ((char *) (T)
(gdb) n971 off = att_addlength_pointer (off, thisatt- > attlen, tp + off); (gdb) 973 if (thisatt- > attlen attlen$34 =-1 (gdb) n974 slow = true; / * can't use attcacheoff anymore * / (gdb) 926 for (; attnum)
< natts; attnum++)(gdb) 928 Form_pg_attribute thisatt = TupleDescAttr(tupleDesc, attnum);(gdb) 930 if (hasnulls && att_isnull(attnum, bp))(gdb) 938 isnull[attnum] = false;(gdb) 940 if (!slow && thisatt->Attcacheoff > = 0) (gdb) 942 else if (thisatt- > attlen = =-1) (gdb) 950 if (! slow & & (gdb) 955 off = att_align_pointer (off, thisatt- > attalign,-1, (gdb) 957 slow = true; (gdb) p off$35 = 9 (gdb) n969 values [attnum] = fetchatt (thisatt, tp + off) (gdb) p * thisatt$36 = {attrelid = 131110, attname = {data = "col_char",'\ 000'}, atttypid = 1042, attstattarget =-1, attlen =-1, attnum = 3, attndims = 0, attcacheoff =-1, atttypmod = 14, attbyval = false, attstorage = 120'x, attalign = 105'I, attnotnull = false, atthasdef = false, atthasmissing = false, attidentity = 0'\ 000, attgenerated = 0'\ 000, attisdropped = false, attislocal = true, attinhcount = 0 Attcollation = 100} (gdb) p (char *) PointerGetDatum ((char *) (tp+off)) $37 = 0x7fe18396e459 "\ 027test" (gdb)
Gets the fourth attribute value, that is, the value of col_double. Note: the logic executed by fetchatt is * ((Datum *) (T)
(gdb) n971 off = att_addlength_pointer (off, thisatt- > attlen, tp + off); (gdb) 973 if (thisatt- > attlen tts_nvalid = attnum; (gdb) 981 * offp = off; (gdb) 982 if (slow) (gdb) 983 slot- > tts_flags | = TTS_FLAG_SLOW (gdb) 986} (gdb) tts_buffer_heap_getsomeattrs (slot=0x12312a0, natts=5) at execTuples.c:677677} (gdb) so far, I believe you have a deeper understanding of "how to get tuple attribute values when PostgreSQL executes a query". You might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!