<commit_before>/*-------------------------------------------------------------------------
 *
 * execBitmapTableScan.c
 *	  Support routines for nodeBitmapTableScan.c
 *
 * Portions Copyright (c) 2014-Present Pivotal Software, Inc.
 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	    src/backend/executor/execBitmapTableScan.c
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include "access/heapam.h"
#include "access/relscan.h"
#include "access/transam.h"
#include "executor/execdebug.h"
#include "executor/nodeBitmapTableScan.h"
#include "pgstat.h"
#include "storage/bufmgr.h"
#include "utils/memutils.h"
#include "miscadmin.h"
#include "parser/parsetree.h"
#include "cdb/cdbvars.h" /* gp_select_invisible */
#include "cdb/cdbfilerepprimary.h"
#include "nodes/tidbitmap.h"

/*
 * Returns BitmapTableScanMethod for a given table type.
 */
static const ScanMethod *
getBitmapTableScanMethod(TableType tableType)
{
	Assert(tableType >= TableTypeHeap && tableType < TableTypeInvalid);

	/*
	 * scanMethods
	 *    Array that specifies different scan methods for various table types.
	 *
	 * The index in this array for a specific table type should match the enum value
	 * defined in TableType.
	 */
	static const ScanMethod scanMethods[] =
	{
		{
			&BitmapHeapScanNext, &BitmapHeapScanBegin, &BitmapHeapScanEnd,
			&BitmapHeapScanReScan, &MarkRestrNotAllowed, &MarkRestrNotAllowed
		},
		{
			&BitmapAOScanNext, &BitmapAOScanBegin, &BitmapAOScanEnd,
			&BitmapAOScanReScan, &MarkRestrNotAllowed, &MarkRestrNotAllowed
		},
		{
			/* The same set of methods serve both AO and AOCO scans */
			&BitmapAOScanNext, &BitmapAOScanBegin, &BitmapAOScanEnd,
			&BitmapAOScanReScan, &MarkRestrNotAllowed, &MarkRestrNotAllowed
		}
	};

	COMPILE_ASSERT(ARRAY_SIZE(scanMethods) == TableTypeInvalid);

	return &scanMethods[tableType];
}

/*
 * Initializes the state relevant to bitmaps.
 */
static inline void
initBitmapState(BitmapTableScanState *scanstate)
{
	if (scanstate->tbmres == NULL)
	{
		scanstate->tbmres =
			palloc0(sizeof(TBMIterateResult) +
					MAX_TUPLES_PER_PAGE * sizeof(OffsetNumber));
	}
}

/*
 * Frees the state relevant to bitmaps.
 */
static inline void
freeBitmapState(BitmapTableScanState *scanstate)
{
	/* BitmapIndexScan is the owner of the bitmap memory. Don't free it here */
	scanstate->tbm = NULL;

	/* BitmapTableScan created the iterator, so it is responsible to free its iterator */
	if (scanstate->tbmres != NULL)
	{
		pfree(scanstate->tbmres);
		scanstate->tbmres = NULL;
	}
}

static TupleTableSlot*
BitmapTableScanPlanQualTuple(BitmapTableScanState *node)
{
	EState	   *estate = node->ss.ps.state;
	Index		scanrelid = ((BitmapTableScan *) node->ss.ps.plan)->scan.scanrelid;
	ExprContext *econtext = node->ss.ps.ps_ExprContext;
	TupleTableSlot *slot = node->ss.ss_ScanTupleSlot;

	/*
	 * Check if we are evaluating PlanQual for tuple of this relation.
	 * Additional checking is not good, but no other way for now. We could
	 * introduce new nodes for this case and handle IndexScan --> NewNode
	 * switching in Init/ReScan plan...
	 */
	if (estate->es_evTuple != NULL &&
		estate->es_evTuple[scanrelid - 1] != NULL)
	{
		if (estate->es_evTupleNull[scanrelid - 1])
		{
			return ExecClearTuple(slot);
		}

		ExecStoreHeapTuple(estate->es_evTuple[scanrelid - 1], slot, InvalidBuffer, false);

		/* Does the tuple meet the original qual conditions? */
		econtext->ecxt_scantuple = slot;

		ResetExprContext(econtext);

		if (!ExecQual(node->bitmapqualorig, econtext, false))
		{
			ExecClearTuple(slot);		/* would not be returned by scan */
		}

		/* Flag for the next call that no more tuples */
		estate->es_evTupleNull[scanrelid - 1] = true;

		return slot;
	}

	return ExecClearTuple(slot);
}

/*
 * Reads a bitmap (with possibly many pages) from the underlying node.
 */
static void
readBitmap(BitmapTableScanState *scanState)
{
	if (scanState->tbm != NULL)
	{
		return;
	}

	Node *tbm = (Node *) MultiExecProcNode(outerPlanState(scanState));

	if (tbm != NULL && (!(IsA(tbm, HashBitmap) ||
						  IsA(tbm, StreamBitmap))))
	{
		elog(ERROR, "unrecognized result from subplan");
	}

	scanState->tbm = tbm;
	scanState->needNewBitmapPage = true;
}

/*
 * Reads the next bitmap page from the current bitmap.
 */
static bool
fetchNextBitmapPage(BitmapTableScanState *scanState)
{
	if (scanState->tbm == NULL)
	{
		return false;
	}

	TBMIterateResult *tbmres = (TBMIterateResult *)scanState->tbmres;

	Assert(scanState->needNewBitmapPage);
<commit_msg>Change one more check to not accept NULL result from MultiExecProcNode().<commit_after>/*-------------------------------------------------------------------------
 *
 * execBitmapTableScan.c
 *	  Support routines for nodeBitmapTableScan.c
 *
 * Portions Copyright (c) 2014-Present Pivotal Software, Inc.
 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	    src/backend/executor/execBitmapTableScan.c
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include "access/heapam.h"
#include "access/relscan.h"
#include "access/transam.h"
#include "executor/execdebug.h"
#include "executor/nodeBitmapTableScan.h"
#include "pgstat.h"
#include "storage/bufmgr.h"
#include "utils/memutils.h"
#include "miscadmin.h"
#include "parser/parsetree.h"
#include "cdb/cdbvars.h" /* gp_select_invisible */
#include "cdb/cdbfilerepprimary.h"
#include "nodes/tidbitmap.h"

/*
 * Returns BitmapTableScanMethod for a given table type.
 */
static const ScanMethod *
getBitmapTableScanMethod(TableType tableType)
{
	Assert(tableType >= TableTypeHeap && tableType < TableTypeInvalid);

	/*
	 * scanMethods
	 *    Array that specifies different scan methods for various table types.
	 *
	 * The index in this array for a specific table type should match the enum value
	 * defined in TableType.
	 */
	static const ScanMethod scanMethods[] =
	{
		{
			&BitmapHeapScanNext, &BitmapHeapScanBegin, &BitmapHeapScanEnd,
			&BitmapHeapScanReScan, &MarkRestrNotAllowed, &MarkRestrNotAllowed
		},
		{
			&BitmapAOScanNext, &BitmapAOScanBegin, &BitmapAOScanEnd,
			&BitmapAOScanReScan, &MarkRestrNotAllowed, &MarkRestrNotAllowed
		},
		{
			/* The same set of methods serve both AO and AOCO scans */
			&BitmapAOScanNext, &BitmapAOScanBegin, &BitmapAOScanEnd,
			&BitmapAOScanReScan, &MarkRestrNotAllowed, &MarkRestrNotAllowed
		}
	};

	COMPILE_ASSERT(ARRAY_SIZE(scanMethods) == TableTypeInvalid);

	return &scanMethods[tableType];
}

/*
 * Initializes the state relevant to bitmaps.
 */
static inline void
initBitmapState(BitmapTableScanState *scanstate)
{
	if (scanstate->tbmres == NULL)
	{
		scanstate->tbmres =
			palloc0(sizeof(TBMIterateResult) +
					MAX_TUPLES_PER_PAGE * sizeof(OffsetNumber));
	}
}

/*
 * Frees the state relevant to bitmaps.
 */
static inline void
freeBitmapState(BitmapTableScanState *scanstate)
{
	/* BitmapIndexScan is the owner of the bitmap memory. Don't free it here */
	scanstate->tbm = NULL;

	/* BitmapTableScan created the iterator, so it is responsible to free its iterator */
	if (scanstate->tbmres != NULL)
	{
		pfree(scanstate->tbmres);
		scanstate->tbmres = NULL;
	}
}

static TupleTableSlot*
BitmapTableScanPlanQualTuple(BitmapTableScanState *node)
{
	EState	   *estate = node->ss.ps.state;
	Index		scanrelid = ((BitmapTableScan *) node->ss.ps.plan)->scan.scanrelid;
	ExprContext *econtext = node->ss.ps.ps_ExprContext;
	TupleTableSlot *slot = node->ss.ss_ScanTupleSlot;

	/*
	 * Check if we are evaluating PlanQual for tuple of this relation.
	 * Additional checking is not good, but no other way for now. We could
	 * introduce new nodes for this case and handle IndexScan --> NewNode
	 * switching in Init/ReScan plan...
	 */
	if (estate->es_evTuple != NULL &&
		estate->es_evTuple[scanrelid - 1] != NULL)
	{
		if (estate->es_evTupleNull[scanrelid - 1])
		{
			return ExecClearTuple(slot);
		}

		ExecStoreHeapTuple(estate->es_evTuple[scanrelid - 1], slot, InvalidBuffer, false);

		/* Does the tuple meet the original qual conditions? */
		econtext->ecxt_scantuple = slot;

		ResetExprContext(econtext);

		if (!ExecQual(node->bitmapqualorig, econtext, false))
		{
			ExecClearTuple(slot);		/* would not be returned by scan */
		}

		/* Flag for the next call that no more tuples */
		estate->es_evTupleNull[scanrelid - 1] = true;

		return slot;
	}

	return ExecClearTuple(slot);
}

/*
 * Reads a bitmap (with possibly many pages) from the underlying node.
 */
static void
readBitmap(BitmapTableScanState *scanState)
{
	if (scanState->tbm != NULL)
	{
		return;
	}

	Node *tbm = (Node *) MultiExecProcNode(outerPlanState(scanState));

	if (!tbm || !(IsA(tbm, HashBitmap) || IsA(tbm, StreamBitmap)))
		elog(ERROR, "unrecognized result from subplan");

	scanState->tbm = tbm;
	scanState->needNewBitmapPage = true;
}

/*
 * Reads the next bitmap page from the current bitmap.
 */
static bool
fetchNextBitmapPage(BitmapTableScanState *scanState)
{
	if (scanState->tbm == NULL)
	{
		return false;
	}

	TBMIterateResult *tbmres = (TBMIterateResult *)scanState->tbmres;

	Assert(scanState->needNewBitmapPage);

{'fraction_non_alphanumeric': 0.14164972718519311, 'fraction_numerical': 0.004493420348775008, 'mean_word_length': 3.75, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 55, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5820065', 'n_tokens_mistral': 3235, 'n_tokens_neox': 3029, 'n_words': 761}