summaryrefslogtreecommitdiff
path: root/src/include
diff options
context:
space:
mode:
Diffstat (limited to 'src/include')
-rw-r--r--src/include/access/htup_details.h2
-rw-r--r--src/include/executor/tuptable.h409
-rw-r--r--src/include/jit/llvmjit.h2
3 files changed, 310 insertions, 103 deletions
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 97d240fdbb0..1867a70f6f3 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -835,7 +835,5 @@ extern MinimalTuple minimal_tuple_from_heap_tuple(HeapTuple htup);
extern size_t varsize_any(void *p);
extern HeapTuple heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc);
extern MinimalTuple minimal_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc);
-struct TupleTableSlot;
-extern void slot_deform_tuple(struct TupleTableSlot *slot, int natts);
#endif /* HTUP_DETAILS_H */
diff --git a/src/include/executor/tuptable.h b/src/include/executor/tuptable.h
index 9470d385309..db5031f5746 100644
--- a/src/include/executor/tuptable.h
+++ b/src/include/executor/tuptable.h
@@ -20,11 +20,20 @@
/*----------
* The executor stores tuples in a "tuple table" which is a List of
- * independent TupleTableSlots. There are several cases we need to handle:
- * 1. physical tuple in a disk buffer page
- * 2. physical tuple constructed in palloc'ed memory
- * 3. "minimal" physical tuple constructed in palloc'ed memory
- * 4. "virtual" tuple consisting of Datum/isnull arrays
+ * independent TupleTableSlots.
+ *
+ * There's various different types of tuple table slots, each being able to
+ * store different types of tuples. Additional types of slots can be added
+ * without modifying core code. The type of a slot is determined by the
+ * TupleTableSlotOps* passed to the slot creation routine. The builtin types
+ * of slots are
+ *
+ * 1. physical tuple in a disk buffer page (TTSOpsBufferHeapTuple)
+ * 2. physical tuple constructed in palloc'ed memory (TTSOpsHeapTuple)
+ * 3. "minimal" physical tuple constructed in palloc'ed memory
+ * (TTSOpsMinimalTuple)
+ * 4. "virtual" tuple consisting of Datum/isnull arrays (TTSOpsVirtual)
+ *
*
* The first two cases are similar in that they both deal with "materialized"
* tuples, but resource management is different. For a tuple in a disk page
@@ -37,39 +46,28 @@
* parallel to case 1. Note that a minimal tuple has no "system columns".
* (Actually, it could have an OID, but we have no need to access the OID.)
*
- * A "virtual" tuple is an optimization used to minimize physical data
- * copying in a nest of plan nodes. Any pass-by-reference Datums in the
- * tuple point to storage that is not directly associated with the
- * TupleTableSlot; generally they will point to part of a tuple stored in
- * a lower plan node's output TupleTableSlot, or to a function result
+ * A "virtual" tuple is an optimization used to minimize physical data copying
+ * in a nest of plan nodes. Until materialized pass-by-reference Datums in
+ * the slot point to storage that is not directly associated with the
+ * TupleTableSlot; generally they will point to part of a tuple stored in a
+ * lower plan node's output TupleTableSlot, or to a function result
* constructed in a plan node's per-tuple econtext. It is the responsibility
- * of the generating plan node to be sure these resources are not released
- * for as long as the virtual tuple needs to be valid. We only use virtual
- * tuples in the result slots of plan nodes --- tuples to be copied anywhere
- * else need to be "materialized" into physical tuples. Note also that a
- * virtual tuple does not have any "system columns".
+ * of the generating plan node to be sure these resources are not released for
+ * as long as the virtual tuple needs to be valid or is materialized. Note
+ * also that a virtual tuple does not have any "system columns".
*
- * It is also possible for a TupleTableSlot to hold both physical and minimal
- * copies of a tuple. This is done when the slot is requested to provide
- * the format other than the one it currently holds. (Originally we attempted
- * to handle such requests by replacing one format with the other, but that
- * had the fatal defect of invalidating any pass-by-reference Datums pointing
- * into the existing slot contents.) Both copies must contain identical data
- * payloads when this is the case.
+ * The Datum/isnull arrays of a TupleTableSlot serve double duty. For virtual
+ * slots they they are the authoritative data. For the other builtin slots,
+ * the arrays contain data extracted from the tuple. (In this state, any
+ * pass-by-reference Datums point into the physical tuple.) The extracted
+ * information is built "lazily", ie, only as needed. This serves to avoid
+ * repeated extraction of data from the physical tuple.
*
- * The Datum/isnull arrays of a TupleTableSlot serve double duty. When the
- * slot contains a virtual tuple, they are the authoritative data. When the
- * slot contains a physical tuple, the arrays contain data extracted from
- * the tuple. (In this state, any pass-by-reference Datums point into
- * the physical tuple.) The extracted information is built "lazily",
- * ie, only as needed. This serves to avoid repeated extraction of data
- * from the physical tuple.
- *
- * A TupleTableSlot can also be "empty", indicated by flag TTS_EMPTY set in
- * tts_flags, holding no valid data. This is the only valid state for a
- * freshly-created slot that has not yet had a tuple descriptor assigned to it.
- * In this state, TTS_SHOULDFREE should not be set in tts_flag, tts_tuple must
- * be NULL, tts_buffer InvalidBuffer, and tts_nvalid zero.
+ * A TupleTableSlot can also be "empty", indicated by flag TTS_FLAG_EMPTY set
+ * in tts_flags, holding no valid data. This is the only valid state for a
+ * freshly-created slot that has not yet had a tuple descriptor assigned to
+ * it. In this state, TTS_SHOULDFREE should not be set in tts_flag, tts_tuple
+ * must be NULL, tts_buffer InvalidBuffer, and tts_nvalid zero.
*
* The tupleDescriptor is simply referenced, not copied, by the TupleTableSlot
* code. The caller of ExecSetSlotDescriptor() is responsible for providing
@@ -83,32 +81,12 @@
* the slot and should be freed when the slot's reference to the tuple is
* dropped.
*
- * If tts_buffer is not InvalidBuffer, then the slot is holding a pin
- * on the indicated buffer page; drop the pin when we release the
- * slot's reference to that buffer. (tts_shouldFree should always be
- * false in such a case, since presumably tts_tuple is pointing at the
- * buffer page.)
- *
- * tts_nvalid indicates the number of valid columns in the tts_values/isnull
- * arrays. When the slot is holding a "virtual" tuple this must be equal
- * to the descriptor's natts. When the slot is holding a physical tuple
- * this is equal to the number of columns we have extracted (we always
- * extract columns from left to right, so there are no holes).
- *
- * tts_values/tts_isnull are allocated when a descriptor is assigned to the
- * slot; they are of length equal to the descriptor's natts.
+ * tts_values/tts_isnull are allocated either when the slot is created (when
+ * the descriptor is provided), or when a descriptor is assigned to the slot;
+ * they are of length equal to the descriptor's natts.
*
- * tts_mintuple must always be NULL if the slot does not hold a "minimal"
- * tuple. When it does, tts_mintuple points to the actual MinimalTupleData
- * object (the thing to be pfree'd if tts_shouldFreeMin is true). If the slot
- * has only a minimal and not also a regular physical tuple, then tts_tuple
- * points at tts_minhdr and the fields of that struct are set correctly
- * for access to the minimal tuple; in particular, tts_minhdr.t_data points
- * MINIMAL_TUPLE_OFFSET bytes before tts_mintuple. This allows column
- * extraction to treat the case identically to regular physical tuples.
- *
- * TTS_SLOW flag in tts_flags and tts_off are saved state for
- * slot_deform_tuple, and should not be touched by any other code.
+ * The TTS_FLAG_SLOW flag and tts_off are saved state for
+ * slot_deform_heap_tuple, and should not be touched by any other code.
*----------
*/
@@ -116,25 +94,22 @@
#define TTS_FLAG_EMPTY (1 << 1)
#define TTS_EMPTY(slot) (((slot)->tts_flags & TTS_FLAG_EMPTY) != 0)
-/* should pfree tts_tuple? */
+/* should pfree tuple "owned" by the slot? */
#define TTS_FLAG_SHOULDFREE (1 << 2)
#define TTS_SHOULDFREE(slot) (((slot)->tts_flags & TTS_FLAG_SHOULDFREE) != 0)
-/* should pfree tts_mintuple? */
-#define TTS_FLAG_SHOULDFREEMIN (1 << 3)
-#define TTS_SHOULDFREEMIN(slot) (((slot)->tts_flags & TTS_FLAG_SHOULDFREEMIN) != 0)
-
-/* saved state for slot_deform_tuple */
-#define TTS_FLAG_SLOW (1 << 4)
+/* saved state for slot_deform_heap_tuple */
+#define TTS_FLAG_SLOW (1 << 3)
#define TTS_SLOW(slot) (((slot)->tts_flags & TTS_FLAG_SLOW) != 0)
/* fixed tuple descriptor */
-#define TTS_FLAG_FIXED (1 << 5)
+#define TTS_FLAG_FIXED (1 << 4)
#define TTS_FIXED(slot) (((slot)->tts_flags & TTS_FLAG_FIXED) != 0)
struct TupleTableSlotOps;
typedef struct TupleTableSlotOps TupleTableSlotOps;
+/* base tuple table slot type */
typedef struct TupleTableSlot
{
NodeTag type;
@@ -142,28 +117,99 @@ typedef struct TupleTableSlot
uint16 tts_flags; /* Boolean states */
#define FIELDNO_TUPLETABLESLOT_NVALID 2
AttrNumber tts_nvalid; /* # of valid values in tts_values */
-#define FIELDNO_TUPLETABLESLOT_TUPLE 3
- HeapTuple tts_tuple; /* physical tuple, or NULL if virtual */
const TupleTableSlotOps *const tts_ops; /* implementation of slot */
-#define FIELDNO_TUPLETABLESLOT_TUPLEDESCRIPTOR 5
+#define FIELDNO_TUPLETABLESLOT_TUPLEDESCRIPTOR 4
TupleDesc tts_tupleDescriptor; /* slot's tuple descriptor */
- MemoryContext tts_mcxt; /* slot itself is in this context */
- Buffer tts_buffer; /* tuple's buffer, or InvalidBuffer */
-#define FIELDNO_TUPLETABLESLOT_OFF 8
- uint32 tts_off; /* saved state for slot_deform_tuple */
-#define FIELDNO_TUPLETABLESLOT_VALUES 9
+#define FIELDNO_TUPLETABLESLOT_VALUES 5
Datum *tts_values; /* current per-attribute values */
-#define FIELDNO_TUPLETABLESLOT_ISNULL 10
+#define FIELDNO_TUPLETABLESLOT_ISNULL 6
bool *tts_isnull; /* current per-attribute isnull flags */
- MinimalTuple tts_mintuple; /* minimal tuple, or NULL if none */
- HeapTupleData tts_minhdr; /* workspace for minimal-tuple-only case */
+ MemoryContext tts_mcxt; /* slot itself is in this context */
} TupleTableSlot;
/* routines for a TupleTableSlot implementation */
struct TupleTableSlotOps
{
- /* body will be replaced in later commit */
- int dummy;
+ /* Minimum size of the slot */
+ size_t base_slot_size;
+
+ /* Initialization. */
+ void (*init)(TupleTableSlot *slot);
+
+ /* Destruction. */
+ void (*release)(TupleTableSlot *slot);
+
+ /*
+ * Clear the contents of the slot. Only the contents are expected to be
+ * cleared and not the tuple descriptor. Typically an implementation of
+ * this callback should free the memory allocated for the tuple contained
+ * in the slot.
+ */
+ void (*clear)(TupleTableSlot *slot);
+
+ /*
+ * Fill up first natts entries of tts_values and tts_isnull arrays with
+ * values from the tuple contained in the slot. The function may be called
+ * with natts more than the number of attributes available in the tuple,
+ * in which case it should set tts_nvalid to the number of returned
+ * columns.
+ */
+ void (*getsomeattrs)(TupleTableSlot *slot, int natts);
+
+ /*
+ * Returns value of the given system attribute as a datum and sets isnull
+ * to false, if it's not NULL. Throws an error if the slot type does not
+ * support system attributes.
+ */
+ Datum (*getsysattr)(TupleTableSlot *slot, int attnum, bool *isnull);
+
+ /*
+ * Make the contents of the slot solely depend on the slot, and not on
+ * underlying resources (like another memory context, buffers, etc).
+ */
+ void (*materialize)(TupleTableSlot *slot);
+
+ /*
+ * Copy the contents of the source slot into the destination slot's own
+ * context. Invoked using callback of the destination slot.
+ */
+ void (*copyslot) (TupleTableSlot *dstslot, TupleTableSlot *srcslot);
+
+ /*
+ * Return a heap tuple "owned" by the slot. It is slot's responsibility to
+ * free the memory consumed by the heap tuple. If the slot can not "own" a
+ * heap tuple, it should not implement this callback and should set it as
+ * NULL.
+ */
+ HeapTuple (*get_heap_tuple)(TupleTableSlot *slot);
+
+ /*
+ * Return a minimal tuple "owned" by the slot. It is slot's responsibility
+ * to free the memory consumed by the minimal tuple. If the slot can not
+ * "own" a minimal tuple, it should not implement this callback and should
+ * set it as NULL.
+ */
+ MinimalTuple (*get_minimal_tuple)(TupleTableSlot *slot);
+
+ /*
+ * Return a copy of heap tuple representing the contents of the slot. The
+ * copy needs to be palloc'd in the current memory context. The slot
+ * itself is expected to remain unaffected. It is *not* expected to have
+ * meaningful "system columns" in the copy. The copy is not be "owned" by
+ * the slot i.e. the caller has to take responsibilty to free memory
+ * consumed by the slot.
+ */
+ HeapTuple (*copy_heap_tuple)(TupleTableSlot *slot);
+
+ /*
+ * Return a copy of minimal tuple representing the contents of the slot. The
+ * copy needs to be palloc'd in the current memory context. The slot
+ * itself is expected to remain unaffected. It is *not* expected to have
+ * meaningful "system columns" in the copy. The copy is not be "owned" by
+ * the slot i.e. the caller has to take responsibilty to free memory
+ * consumed by the slot.
+ */
+ MinimalTuple (*copy_minimal_tuple)(TupleTableSlot *slot);
};
/*
@@ -173,10 +219,68 @@ struct TupleTableSlotOps
extern PGDLLIMPORT const TupleTableSlotOps TTSOpsVirtual;
extern PGDLLIMPORT const TupleTableSlotOps TTSOpsHeapTuple;
extern PGDLLIMPORT const TupleTableSlotOps TTSOpsMinimalTuple;
-extern PGDLLIMPORT const TupleTableSlotOps TTSOpsBufferTuple;
+extern PGDLLIMPORT const TupleTableSlotOps TTSOpsBufferHeapTuple;
+
+#define TTS_IS_VIRTUAL(slot) ((slot)->tts_ops == &TTSOpsVirtual)
+#define TTS_IS_HEAPTUPLE(slot) ((slot)->tts_ops == &TTSOpsHeapTuple)
+#define TTS_IS_MINIMALTUPLE(slot) ((slot)->tts_ops == &TTSOpsMinimalTuple)
+#define TTS_IS_BUFFERTUPLE(slot) ((slot)->tts_ops == &TTSOpsBufferHeapTuple)
-#define TTS_HAS_PHYSICAL_TUPLE(slot) \
- ((slot)->tts_tuple != NULL && (slot)->tts_tuple != &((slot)->tts_minhdr))
+
+/*
+ * Tuple table slot implementations.
+ */
+
+typedef struct VirtualTupleTableSlot
+{
+ TupleTableSlot base;
+
+ char *data; /* data for materialized slots */
+} VirtualTupleTableSlot;
+
+typedef struct HeapTupleTableSlot
+{
+ TupleTableSlot base;
+
+#define FIELDNO_HEAPTUPLETABLESLOT_TUPLE 1
+ HeapTuple tuple; /* physical tuple */
+#define FIELDNO_HEAPTUPLETABLESLOT_OFF 2
+ uint32 off; /* saved state for slot_deform_heap_tuple */
+} HeapTupleTableSlot;
+
+/* heap tuple residing in a buffer */
+typedef struct BufferHeapTupleTableSlot
+{
+ HeapTupleTableSlot base;
+
+ /*
+ * If buffer is not InvalidBuffer, then the slot is holding a pin on the
+ * indicated buffer page; drop the pin when we release the slot's
+ * reference to that buffer. (TTS_FLAG_SHOULDFREE should not be set be
+ * false in such a case, since presumably tts_tuple is pointing at the
+ * buffer page.)
+ */
+ Buffer buffer; /* tuple's buffer, or InvalidBuffer */
+} BufferHeapTupleTableSlot;
+
+typedef struct MinimalTupleTableSlot
+{
+ TupleTableSlot base;
+
+ /*
+ * In a minimal slot tuple points at minhdr and the fields of that struct
+ * are set correctly for access to the minimal tuple; in particular,
+ * minhdr.t_data points MINIMAL_TUPLE_OFFSET bytes before mintuple. This
+ * allows column extraction to treat the case identically to regular
+ * physical tuples.
+ */
+#define FIELDNO_MINIMALTUPLETABLESLOT_TUPLE 1
+ HeapTuple tuple; /* tuple wrapper */
+ MinimalTuple mintuple; /* minimal tuple, or NULL if none */
+ HeapTupleData minhdr; /* workspace for minimal-tuple-only case */
+#define FIELDNO_MINIMALTUPLETABLESLOT_OFF 4
+ uint32 off; /* saved state for slot_deform_heap_tuple */
+} MinimalTupleTableSlot;
/*
* TupIsNull -- is a TupleTableSlot empty?
@@ -197,37 +301,26 @@ extern void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc);
extern TupleTableSlot *ExecStoreHeapTuple(HeapTuple tuple,
TupleTableSlot *slot,
bool shouldFree);
+extern void ExecForceStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot);
extern TupleTableSlot *ExecStoreBufferHeapTuple(HeapTuple tuple,
TupleTableSlot *slot,
Buffer buffer);
extern TupleTableSlot *ExecStoreMinimalTuple(MinimalTuple mtup,
TupleTableSlot *slot,
bool shouldFree);
-extern TupleTableSlot *ExecClearTuple(TupleTableSlot *slot);
+extern void ExecForceStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot,
+ bool shouldFree);
extern TupleTableSlot *ExecStoreVirtualTuple(TupleTableSlot *slot);
extern TupleTableSlot *ExecStoreAllNullTuple(TupleTableSlot *slot);
-extern HeapTuple ExecCopySlotTuple(TupleTableSlot *slot);
-extern MinimalTuple ExecCopySlotMinimalTuple(TupleTableSlot *slot);
-extern HeapTuple ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shoulFree);
+extern HeapTuple ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree);
extern MinimalTuple ExecFetchSlotMinimalTuple(TupleTableSlot *slot,
bool *shouldFree);
extern Datum ExecFetchSlotHeapTupleDatum(TupleTableSlot *slot);
-extern void ExecMaterializeSlot(TupleTableSlot *slot);
-extern TupleTableSlot *ExecCopySlot(TupleTableSlot *dstslot,
- TupleTableSlot *srcslot);
extern void slot_getmissingattrs(TupleTableSlot *slot, int startAttNum,
int lastAttNum);
-extern Datum slot_getattr(TupleTableSlot *slot, int attnum,
- bool *isnull);
-
-/* in access/common/heaptuple.c */
-extern bool slot_attisnull(TupleTableSlot *slot, int attnum);
-extern bool slot_getsysattr(TupleTableSlot *slot, int attnum,
- Datum *value, bool *isnull);
-extern Datum getmissingattr(TupleDesc tupleDesc,
- int attnum, bool *isnull);
extern void slot_getsomeattrs_int(TupleTableSlot *slot, int attnum);
+
#ifndef FRONTEND
/*
@@ -253,6 +346,120 @@ slot_getallattrs(TupleTableSlot *slot)
slot_getsomeattrs(slot, slot->tts_tupleDescriptor->natts);
}
-#endif
+
+/*
+ * slot_attisnull
+ *
+ * Detect whether an attribute of the slot is null, without actually fetching
+ * it.
+ */
+static inline bool
+slot_attisnull(TupleTableSlot *slot, int attnum)
+{
+ AssertArg(attnum > 0);
+
+ if (attnum > slot->tts_nvalid)
+ slot_getsomeattrs(slot, attnum);
+
+ return slot->tts_isnull[attnum - 1];
+}
+
+/*
+ * slot_getattr - fetch one attribute of the slot's contents.
+ */
+static inline Datum
+slot_getattr(TupleTableSlot *slot, int attnum,
+ bool *isnull)
+{
+ AssertArg(attnum > 0);
+
+ if (attnum > slot->tts_nvalid)
+ slot_getsomeattrs(slot, attnum);
+
+ *isnull = slot->tts_isnull[attnum - 1];
+
+ return slot->tts_values[attnum - 1];
+}
+
+/*
+ * slot_getsysattr - fetch a system attribute of the slot's current tuple.
+ *
+ * If the slot type does not contain system attributes, this will throw an
+ * error. Hence before calling this function, callers should make sure that
+ * the slot type is the one that supports system attributes.
+ */
+static inline Datum
+slot_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
+{
+ AssertArg(attnum < 0); /* caller error */
+
+ /* Fetch the system attribute from the underlying tuple. */
+ return slot->tts_ops->getsysattr(slot, attnum, isnull);
+}
+
+/*
+ * ExecClearTuple - clear the slot's contents
+ */
+static inline TupleTableSlot *
+ExecClearTuple(TupleTableSlot *slot)
+{
+ slot->tts_ops->clear(slot);
+
+ return slot;
+}
+
+/* ExecMaterializeSlot - force a slot into the "materialized" state.
+ *
+ * This causes the slot's tuple to be a local copy not dependent on any
+ * external storage (i.e. pointing into a Buffer, or having allocations in
+ * another memory context).
+ *
+ * A typical use for this operation is to prepare a computed tuple for being
+ * stored on disk. The original data may or may not be virtual, but in any
+ * case we need a private copy for heap_insert to scribble on.
+ */
+static inline void
+ExecMaterializeSlot(TupleTableSlot *slot)
+{
+ slot->tts_ops->materialize(slot);
+}
+
+/*
+ * ExecCopySlotHeapTuple - return HeapTuple allocated in caller's context
+ */
+static inline HeapTuple
+ExecCopySlotHeapTuple(TupleTableSlot *slot)
+{
+ Assert(!TTS_EMPTY(slot));
+
+ return slot->tts_ops->copy_heap_tuple(slot);
+}
+
+/*
+ * ExecCopySlotMinimalTuple - return MinimalTuple allocated in caller's context
+ */
+static inline MinimalTuple
+ExecCopySlotMinimalTuple(TupleTableSlot *slot)
+{
+ return slot->tts_ops->copy_minimal_tuple(slot);
+}
+
+/*
+ * ExecCopySlot - copy one slot's contents into another.
+ *
+ * If a source's system attributes are supposed to be accessed in the target
+ * slot, the target slot and source slot types need to match.
+ */
+static inline TupleTableSlot *
+ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
+{
+ Assert(!TTS_EMPTY(srcslot));
+
+ dstslot->tts_ops->copyslot(dstslot, srcslot);
+
+ return dstslot;
+}
+
+#endif /* FRONTEND */
#endif /* TUPTABLE_H */
diff --git a/src/include/jit/llvmjit.h b/src/include/jit/llvmjit.h
index 05c9740bc5e..1639846d8b5 100644
--- a/src/include/jit/llvmjit.h
+++ b/src/include/jit/llvmjit.h
@@ -65,6 +65,8 @@ extern LLVMTypeRef TypeStorageBool;
extern LLVMTypeRef StructtupleDesc;
extern LLVMTypeRef StructHeapTupleData;
extern LLVMTypeRef StructTupleTableSlot;
+extern LLVMTypeRef StructHeapTupleTableSlot;
+extern LLVMTypeRef StructMinimalTupleTableSlot;
extern LLVMTypeRef StructMemoryContextData;
extern LLVMTypeRef StructFunctionCallInfoData;
extern LLVMTypeRef StructExprContext;