Add an experimental location(X) SQL function that attempt to return the
location of the payload within the database for the record that contains
column X.  location(X) returns NULL if X is not an ordinary table column or
if SQLite cannot figure out the location because it is using a covering index.

FossilOrigin-Name: 51be9558164301c5dd4df23ab8b3e67de0b522f8d36f79f3d84d45d3dc2a83a4
diff --git a/src/btree.c b/src/btree.c
index 0fa00a2..d17cbde 100644
--- a/src/btree.c
+++ b/src/btree.c
@@ -4433,6 +4433,19 @@
 }
 
 /*
+** Return the offset into the database file for the start of the
+** payload to which the cursor is pointing.
+*/
+i64 sqlite3BtreeLocation(BtCursor *pCur){
+  assert( cursorHoldsMutex(pCur) );
+  assert( pCur->eState==CURSOR_VALID );
+  assert( pCur->curIntKey );
+  getCellInfo(pCur);
+  return (i64)pCur->pBt->pageSize*(i64)pCur->pPage->pgno +
+         (i64)(pCur->info.pPayload - pCur->pPage->aData);
+}
+
+/*
 ** Return the number of bytes of payload for the entry that pCur is
 ** currently pointing to.  For table btrees, this will be the amount
 ** of data.  For index btrees, this will be the size of the key.
diff --git a/src/btree.h b/src/btree.h
index e2c271c..43c0b9a 100644
--- a/src/btree.h
+++ b/src/btree.h
@@ -291,6 +291,7 @@
 int sqlite3BtreeEof(BtCursor*);
 int sqlite3BtreePrevious(BtCursor*, int flags);
 i64 sqlite3BtreeIntegerKey(BtCursor*);
+i64 sqlite3BtreeLocation(BtCursor*);
 int sqlite3BtreePayload(BtCursor*, u32 offset, u32 amt, void*);
 const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt);
 u32 sqlite3BtreePayloadSize(BtCursor*);
diff --git a/src/expr.c b/src/expr.c
index 524e539..b7c64d3 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -3871,9 +3871,18 @@
         if( !pColl ) pColl = db->pDfltColl; 
         sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ);
       }
-      sqlite3VdbeAddOp4(v, pParse->iSelfTab ? OP_PureFunc0 : OP_Function0,
-                        constMask, r1, target, (char*)pDef, P4_FUNCDEF);
-      sqlite3VdbeChangeP5(v, (u8)nFarg);
+      if( pDef->funcFlags & SQLITE_FUNC_LOCATION ){
+        Expr *pArg = pFarg->a[0].pExpr;
+        if( pArg->op==TK_COLUMN ){
+          sqlite3VdbeAddOp2(v, OP_Location, pArg->iTable, target);
+        }else{
+          sqlite3VdbeAddOp2(v, OP_Null, 0, target);
+        }
+      }else{
+        sqlite3VdbeAddOp4(v, pParse->iSelfTab ? OP_PureFunc0 : OP_Function0,
+                          constMask, r1, target, (char*)pDef, P4_FUNCDEF);
+        sqlite3VdbeChangeP5(v, (u8)nFarg);
+      }
       if( nFarg && constMask==0 ){
         sqlite3ReleaseTempRange(pParse, r1, nFarg);
       }
diff --git a/src/func.c b/src/func.c
index 7528fa8..f81c486 100644
--- a/src/func.c
+++ b/src/func.c
@@ -1799,6 +1799,8 @@
 #ifdef SQLITE_DEBUG
     FUNCTION2(affinity,          1, 0, 0, noopFunc,  SQLITE_FUNC_AFFINITY),
 #endif
+    FUNCTION2(location,          1, 0, 0, noopFunc,  SQLITE_FUNC_LOCATION|
+                                                     SQLITE_FUNC_TYPEOF),
     FUNCTION(ltrim,              1, 1, 0, trimFunc         ),
     FUNCTION(ltrim,              2, 1, 0, trimFunc         ),
     FUNCTION(rtrim,              1, 2, 0, trimFunc         ),
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index efe823a..f85682a 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -1630,6 +1630,7 @@
 #define SQLITE_FUNC_SLOCHNG  0x2000 /* "Slow Change". Value constant during a
                                     ** single query - might change over time */
 #define SQLITE_FUNC_AFFINITY 0x4000 /* Built-in affinity() function */
+#define SQLITE_FUNC_LOCATION 0x8000 /* Built-in location() function */
 
 /*
 ** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
diff --git a/src/vdbe.c b/src/vdbe.c
index cfe18a9..74cf82c 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -2349,6 +2349,26 @@
   break;
 }
 
+/* Opcode: Location P1 P2 * * *
+** Synopsis: r[P2] = location(P1)
+**
+** Store in register r[P2] the location in the database file that is the
+** start of the payload for the record at which that cursor P1 is currently
+** pointing.
+*/
+case OP_Location: {          /* out2 */
+  VdbeCursor *pC;    /* The VDBE cursor */
+  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+  pC = p->apCsr[pOp->p1];
+  pOut = out2Prerelease(p, pOp);
+  if( pC==0 || pC->eCurType!=CURTYPE_BTREE ){
+    pOut->flags = MEM_Null;
+  }else{
+    pOut->u.i = sqlite3BtreeLocation(pC->uc.pCursor);
+  }
+  break;
+}
+
 /* Opcode: Column P1 P2 P3 P4 P5
 ** Synopsis: r[P3]=PX
 **