new NLJ全部代码

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/zhoutianzi12/article/details/91902899
static TupleTableSlot *
ExecNestLoop(PlanState *pstate)
{
	NestLoopState *node = castNode(NestLoopState, pstate);
	NestLoop   *nl;
	PlanState  *innerPlan;
	PlanState  *outerPlan;
	TupleTableSlot *outerTupleSlot;
	TupleTableSlot *innerTupleSlot;
	ExprState  *joinqual;
	ExprState  *otherqual;
	ExprContext *econtext;
	ListCell   *lc;

	CHECK_FOR_INTERRUPTS();

	/*
	 * get information from the node
	 */
	ENL1_printf("getting info from node");

	nl = (NestLoop *) node->js.ps.plan;
	joinqual = node->js.joinqual;
	otherqual = node->js.ps.qual;
	outerPlan = outerPlanState(node);
	innerPlan = innerPlanState(node);
	econtext = node->js.ps.ps_ExprContext;

	/*
	 * Reset per-tuple memory context to free any expression evaluation
	 * storage allocated in the previous tuple cycle.
	 */
	ResetExprContext(econtext);

	



	/* ----------------------------------------------------------------
	*		YUSUR CODE START: start acceleration.
	* ----------------------------------------------------------------
	*/
	
	if (DBLIB_ENABLED)
	{

		/*
		* we execute join only when it's the first loop, so this number
		* indicates the number of loop.
		*/
		static int dblib_nestloop_num = 0;//第几次调用呢?这里的static的意思是函数结束时候,这个变量保持原来的值,这样第二次第三次仍然可以使用这个变量原来的值
		static TupleTableSlot *dblib_result_tupleslot = NULL;//这个就是一个指针呗,留着指向结果使用
		/*
		* We don't accelerate join including index scan.
		*/
		if (outerPlan->type != T_IndexScanState && innerPlan->type != T_IndexScanState)//没有索引的时候我们才加速哦
		{
			/*
			* Iidentifying the result slots and 'join on' param slots.
			* now we only support one column data per table.
			* We new result Datum **, allocate them into dblib_result_tupleslot.
			*/

			static int *dblib_output_qual_index = NULL;//盛放一对一对的index couple哦,注意static的作用
			static int dblib_output_index_col = 0;//有多少组呢?


			static Datum *dblib_outer_output_datums = NULL;//输入的join的Datum数组,我们现在只支持一个join 条件
			static bool *dblib_outer_output_tts_isnull = NULL;//这个数组是否有些值是空的呢

			static Datum *dblib_inner_output_datums = NULL;//输入的join的Datum数组,我们现在只支持一个join 条件
			static bool *dblib_inner_output_tts_isnull = NULL;//这个数组是否有些值是空的呢





			/*result related to inner tuple. The dblib_result_attnum is the index in result tuple,
			* and the dblib_inner_var_attnum is the index in inner tuple*/
			static int *dblib_innerresult_attnum = NULL;//dblib_innerresult_attnum[]是一个数组,里面有DBLIB_ATTR_NUM(4)个int数字
			static int *dblib_outerresult_attnum = NULL;//dblib_outerresult_attnum[]是一个数组,里面有DBLIB_ATTR_NUM(4)个int数字
			static int	*dblib_inner_var_attnum = NULL;//
			static int *dblib_outer_var_attnum = NULL;//
			static int dblib_resultattr_valid_num = 0, dblib_innerattr_valid_num = 0,
				dblib_outerattr_valid_num = 0;//这个变量在结果元组中的index,在内层的index,在外层的index
			static int dblib_outer_col = 0, dblib_inner_col = 0;  //这个简单,就是内层和外层分别有多少个呢??


			/*
			* Identifying the input slots for KPU kernel. now we only support 1 join condition.
			*/
			TupleTableSlot *dblib_temp_tupleslot;//这个作为函数内的临时变量
			Datum *dblib_input_inner = NULL;//这个作为函数内的临时变量
			Datum *dblib_input_outer = NULL;//这个作为函数内的临时变量

			int dblib_i = 0;
			int dblib_inner_fetch_attnum, dblib_outer_fetch_attnum, dblib_inner_join_attnum,
				dblib_outer_join_attnum;//小于这个的值都会被解析

			unsigned int dblib_join_funcid;

			/*
			* If it's the first loop.
			*/
			if (dblib_nestloop_num == 0) {
				/*
				* Allocate necessary memory
				*/
				dblib_input_inner = (Datum *)malloc(DBLIB_INPUTSLOTS_NUM * sizeof(Datum));//把临时变量搞成数组
				dblib_input_outer = (Datum *)malloc(DBLIB_INPUTSLOTS_NUM * sizeof(Datum));//把临时变量搞成数组

				dblib_output_qual_index = (int *)malloc(2 * DBLIB_OUTPUTSLOTS_NUM * sizeof(int));//把临时变量搞成数组


				dblib_innerresult_attnum = (int *)malloc(DBLIB_ATTR_NUM * sizeof(int));//只有四个数的数组
				dblib_outerresult_attnum = (int *)malloc(DBLIB_ATTR_NUM * sizeof(int));//只有四个数的数组
				dblib_inner_var_attnum = (int *)malloc(DBLIB_ATTR_NUM * sizeof(int));//只有四个数的数组
				dblib_outer_var_attnum = (int *)malloc(DBLIB_ATTR_NUM * sizeof(int));//只有四个数的数组

				/*
				* extract join information from joinqual
				*/
				for (; dblib_i < joinqual->steps_len; dblib_i++)
				{
					switch ((joinqual->steps + dblib_i)->opcode)
					{
					case EEOP_INNER_FETCHSOME:
						dblib_inner_fetch_attnum = (joinqual->steps + dblib_i)->d.fetch.last_var;//意思是从内层中取出那些个数的数据呢?
						break;
					case EEOP_OUTER_FETCHSOME:
						dblib_outer_fetch_attnum = (joinqual->steps + dblib_i)->d.fetch.last_var;//意思是从外层中取出那些个数的数据呢?
						break;
					case EEOP_INNER_VAR:
						dblib_inner_join_attnum = (joinqual->steps + dblib_i)->d.var.attnum;//连接的属性
						break;
					case EEOP_OUTER_VAR:
						dblib_outer_join_attnum = (joinqual->steps + dblib_i)->d.var.attnum;//连接的属性
						break;
					case EEOP_FUNCEXPR_STRICT:
						dblib_join_funcid = (joinqual->steps + dblib_i)->d.func.finfo->fn_oid;//连接运算
						break;

					default:
						;
					}
				}
				/*
				* extract result information from ps_ProjInfo
				*/
				ExprState *dblib_pi_state = &(node->js.ps.ps_ProjInfo->pi_state);
				for (dblib_i = 0; dblib_i < dblib_pi_state->steps_len; dblib_i++)
				{
					switch ((dblib_pi_state->steps + dblib_i)->opcode)
					{
					case EEOP_INNER_FETCHSOME:
						if (dblib_inner_fetch_attnum < (dblib_pi_state->steps + dblib_i)->d.fetch.last_var)
							dblib_inner_fetch_attnum = (dblib_pi_state->steps + dblib_i)->d.fetch.last_var;//哦,这下明白了
						break;
					case EEOP_OUTER_FETCHSOME:
						if (dblib_outer_fetch_attnum < (dblib_pi_state->steps + dblib_i)->d.fetch.last_var)
							dblib_outer_fetch_attnum = (dblib_pi_state->steps + dblib_i)->d.fetch.last_var;//哦,这下明白了
						break;
					case EEOP_ASSIGN_INNER_VAR:
						dblib_innerresult_attnum[dblib_innerattr_valid_num] =
							(dblib_pi_state->steps + dblib_i)->d.assign_var.resultnum;
						dblib_inner_var_attnum[dblib_innerattr_valid_num] =
							(dblib_pi_state->steps + dblib_i)->d.assign_var.attnum;
						dblib_innerattr_valid_num++;
						break;
					case EEOP_ASSIGN_OUTER_VAR:
						dblib_outerresult_attnum[dblib_outerattr_valid_num] =
							(dblib_pi_state->steps + dblib_i)->d.assign_var.resultnum;
						dblib_outer_var_attnum[dblib_outerattr_valid_num] =
							(dblib_pi_state->steps + dblib_i)->d.assign_var.attnum;
						dblib_outerattr_valid_num++;
						break;
					default:
						;
					}
				}
				/*
				* initialize dblib_output_datums
				*/
				dblib_resultattr_valid_num = dblib_innerattr_valid_num + dblib_outerattr_valid_num;
				if (dblib_resultattr_valid_num > 0) {

					dblib_outer_output_datums = (Datum *)malloc(DBLIB_OUTPUTSLOTS_NUM *
						dblib_outerattr_valid_num * sizeof(Datum));

					dblib_outer_output_tts_isnull = (bool *)malloc(DBLIB_OUTPUTSLOTS_NUM *
						dblib_outerattr_valid_num * sizeof(bool));

					dblib_inner_output_datums = (Datum *)malloc(DBLIB_OUTPUTSLOTS_NUM *
						dblib_innerattr_valid_num * sizeof(Datum));

					dblib_inner_output_tts_isnull = (bool *)malloc(DBLIB_OUTPUTSLOTS_NUM *
						dblib_innerattr_valid_num * sizeof(bool));
				}




				/*
				* getting outer tuples and result slots related to outer tuples
				*/
				dblib_i = 0;
				ENL1_printf("DBLIB getting outer tuples");
				dblib_temp_tupleslot = ExecProcNode(outerPlan);
				while (!(TupIsNull(dblib_temp_tupleslot)) && (dblib_i < DBLIB_INPUTSLOTS_NUM))
				{
					/* Assign outer slots inputs*/
					//(joinqual->steps + 1)->d.fetch.last_var, joinqual->steps->d.var.attnum
					slot_getsomeattrs(dblib_temp_tupleslot, dblib_outer_fetch_attnum);
					/* Assign outer intputs*/
					*(dblib_input_outer + dblib_i) = dblib_temp_tupleslot->tts_values[dblib_outer_join_attnum];
					/* Assign output datum*/
					for (int dblib_j = 0; dblib_j < dblib_outerattr_valid_num; dblib_j++)
					{
						int dblib_temp_index1 = dblib_i * dblib_outerattr_valid_num +
							dblib_j;
						int dblib_temp_index2 = dblib_outer_var_attnum[dblib_j];

						dblib_outer_output_datums[dblib_temp_index1] =
							dblib_temp_tupleslot->tts_values[dblib_temp_index2];
						dblib_outer_output_tts_isnull[dblib_temp_index1] =
							dblib_temp_tupleslot->tts_isnull[dblib_temp_index2];

					}

					dblib_temp_tupleslot = ExecProcNode(outerPlan);
					dblib_i++;
				}
				dblib_outer_col = dblib_i;


				/*
				* getting inner tuples and result slots related to inner tuples
				*/
				dblib_i = 0;
				ENL1_printf("DBLIB getting inner tuples");
				dblib_temp_tupleslot = ExecProcNode(innerPlan);
				while (!(TupIsNull(dblib_temp_tupleslot)) && (dblib_i < DBLIB_INPUTSLOTS_NUM))
				{
					/* Assign outer slots inputs */
					//(joinqual->steps + 1)->d.fetch.last_var, joinqual->steps->d.var.attnum
					slot_getsomeattrs(dblib_temp_tupleslot, dblib_inner_fetch_attnum);
					/* Assign inner inputs*/
					*(dblib_input_inner + dblib_i) = dblib_temp_tupleslot->tts_values[dblib_inner_join_attnum];
					/* Assign output datum*/
					for (int dblib_j = 0; dblib_j < dblib_innerattr_valid_num; dblib_j++)
					{

						int dblib_temp_index1 = dblib_i * dblib_innerattr_valid_num +
							dblib_j;
						int dblib_temp_index2 = dblib_inner_var_attnum[dblib_j];

						dblib_inner_output_datums[dblib_temp_index1] =
							dblib_temp_tupleslot->tts_values[dblib_temp_index2];
						dblib_inner_output_tts_isnull[dblib_temp_index1] =
							dblib_temp_tupleslot->tts_isnull[dblib_temp_index2];

					}

					dblib_temp_tupleslot = ExecProcNode(innerPlan);
					dblib_i++;
				}
				dblib_inner_col = dblib_i;

				/*
				* execute join and calculate result slots
				*/
				dblib_output_index_col = DblibNestLoopJoin(dblib_output_qual_index, dblib_input_outer,
					dblib_input_inner, dblib_outer_col, dblib_inner_col, dblib_join_funcid);

				/*
				* Mark the end position of qual_index
				*/
				dblib_output_qual_index[dblib_output_index_col * 2] = -1;
				dblib_output_qual_index[dblib_output_index_col * 2 + 1] = -1;

				/*
				* We need to use ExecProject to initialize some status of node,
				* otherwise, it's forbidden to return dblib_result_tupleslot;
				*/
				outerTupleSlot = ExecProcNode(outerPlan);
				innerTupleSlot = ExecProcNode(innerPlan);
				while (TupIsNull(innerTupleSlot) || TupIsNull(outerTupleSlot))
				{
					ENL1_printf("rescanning inner plan");
					ExecReScan(outerPlan);
					outerTupleSlot = ExecProcNode(outerPlan);
					ExecReScan(innerPlan);
					innerTupleSlot = ExecProcNode(innerPlan);
				}
				econtext->ecxt_outertuple = outerTupleSlot;
				econtext->ecxt_innertuple = innerTupleSlot;
				dblib_result_tupleslot = ExecProject(node->js.ps.ps_ProjInfo);
			}



			/*
			* return one tuple each time
			*/






			for (dblib_i = 0; dblib_i < dblib_output_index_col; dblib_i++)
			{
				int dblib_temp_i = dblib_i * 2;
				int dblib_outer_valid_index = dblib_output_qual_index[dblib_temp_i];
				int dblib_inner_valid_index = dblib_output_qual_index[dblib_temp_i + 1];



				if (dblib_outer_valid_index > -1 &&
					dblib_inner_valid_index > -1)
				{

					node->nl_MatchedOuter = true;
					node->nl_NeedNewOuter = true;


					dblib_result_tupleslot = node->js.ps.ps_ProjInfo->pi_state.resultslot;
					ExecClearTuple(dblib_result_tupleslot);
					dblib_result_tupleslot->tts_isempty = false;
					dblib_result_tupleslot->tts_nvalid =
						dblib_result_tupleslot->tts_tupleDescriptor->natts;

					/*
					* Assign outer output datums
					*/
					for (int dblib_j = 0; dblib_j < dblib_outerattr_valid_num; dblib_j++)
					{
						int dblib_temp_index1 = dblib_outerresult_attnum[dblib_j];
						int dblib_temp_index2 = dblib_outer_valid_index *
							dblib_outerattr_valid_num + dblib_j;
						dblib_result_tupleslot->tts_values[dblib_temp_index1] =
							dblib_outer_output_datums[dblib_temp_index2];
						dblib_result_tupleslot->tts_isnull[dblib_temp_index1] =
							dblib_outer_output_tts_isnull[dblib_temp_index2];
					}



					/*
					* Assign inner output datums
					*/
					for (int dblib_j = 0; dblib_j < dblib_innerattr_valid_num; dblib_j++)
					{
						int dblib_temp_index1 = dblib_innerresult_attnum[dblib_j];
						int dblib_temp_index2 = dblib_inner_valid_index *
							dblib_innerattr_valid_num + dblib_j;

						dblib_result_tupleslot->tts_values[dblib_temp_index1] =
							dblib_inner_output_datums[dblib_temp_index2];

						dblib_result_tupleslot->tts_isnull[dblib_temp_index1] =
							dblib_inner_output_tts_isnull[dblib_temp_index2];

					}

					dblib_output_qual_index[dblib_temp_i] = -1;
					dblib_output_qual_index[dblib_temp_i + 1] = -1;
					dblib_nestloop_num++;
			
					return dblib_result_tupleslot;
				}
			}



			dblib_nestloop_num = 0;
			dblib_resultattr_valid_num = 0;
			dblib_innerattr_valid_num = 0;
			dblib_outerattr_valid_num = 0;
			dblib_output_index_col = 0;
			dblib_outer_col = 0;
			dblib_inner_col = 0;


			free(dblib_input_inner);
			free(dblib_input_outer);
			free(dblib_innerresult_attnum);
			free(dblib_outerresult_attnum);
			free(dblib_inner_var_attnum);
			free(dblib_outer_var_attnum);
			free(dblib_outer_output_datums);
			free(dblib_outer_output_tts_isnull);
			free(dblib_inner_output_datums);
			free(dblib_inner_output_tts_isnull);
			free(dblib_output_qual_index);


			dblib_innerresult_attnum = NULL;
			dblib_outerresult_attnum = NULL;
			dblib_inner_var_attnum = NULL;
			dblib_outer_var_attnum = NULL;
			dblib_outer_output_datums = NULL;
			dblib_outer_output_tts_isnull = NULL;
			dblib_inner_output_datums = NULL;
			dblib_inner_output_tts_isnull = NULL;
			dblib_output_qual_index = NULL;


			/* If all valid result slots are returned,
			* return NULL.
			*/
			return NULL;
		}


	}
	/* ----------------------------------------------------------------
	*		YUSUR CODE END
	* ----------------------------------------------------------------
	*/


	/*
	* Ok, everything is setup for the join so now loop until we return a
	* qualifying join tuple.
	*/
	ENL1_printf("entering main loop");

	for (;;)
	{
		/*
		 * If we don't have an outer tuple, get the next one and reset the
		 * inner scan.
		 */
		if (node->nl_NeedNewOuter)
		{
			ENL1_printf("getting new outer tuple");
			outerTupleSlot = ExecProcNode(outerPlan);

			/*
			 * if there are no more outer tuples, then the join is complete..
			 */
			if (TupIsNull(outerTupleSlot))
			{
				ENL1_printf("no outer tuple, ending join");
				return NULL;
			}

			ENL1_printf("saving new outer tuple information");
			econtext->ecxt_outertuple = outerTupleSlot;
			node->nl_NeedNewOuter = false;
			node->nl_MatchedOuter = false;

			/*
			 * fetch the values of any outer Vars that must be passed to the
			 * inner scan, and store them in the appropriate PARAM_EXEC slots.
			 */
			foreach(lc, nl->nestParams)
			{
				NestLoopParam *nlp = (NestLoopParam *) lfirst(lc);
				int			paramno = nlp->paramno;
				ParamExecData *prm;

				prm = &(econtext->ecxt_param_exec_vals[paramno]);
				/* Param value should be an OUTER_VAR var */
				Assert(IsA(nlp->paramval, Var));
				Assert(nlp->paramval->varno == OUTER_VAR);
				Assert(nlp->paramval->varattno > 0);
				prm->value = slot_getattr(outerTupleSlot,
										  nlp->paramval->varattno,
										  &(prm->isnull));
				/* Flag parameter value as changed */
				innerPlan->chgParam = bms_add_member(innerPlan->chgParam,
													 paramno);
			}

			/*
			 * now rescan the inner plan
			 */
			ENL1_printf("rescanning inner plan");
			ExecReScan(innerPlan);
		}

		/*
		 * we have an outerTuple, try to get the next inner tuple.
		 */
		ENL1_printf("getting new inner tuple");

		innerTupleSlot = ExecProcNode(innerPlan);
		econtext->ecxt_innertuple = innerTupleSlot;
		

		if (TupIsNull(innerTupleSlot))
		{
			ENL1_printf("no inner tuple, need new outer tuple");

			node->nl_NeedNewOuter = true;

			if (!node->nl_MatchedOuter &&
				(node->js.jointype == JOIN_LEFT ||
				 node->js.jointype == JOIN_ANTI))
			{
				/*
				 * We are doing an outer join and there were no join matches
				 * for this outer tuple.  Generate a fake join tuple with
				 * nulls for the inner tuple, and return it if it passes the
				 * non-join quals.
				 */
				econtext->ecxt_innertuple = node->nl_NullInnerTupleSlot;

				ENL1_printf("testing qualification for outer-join tuple");

				if (otherqual == NULL || ExecQual(otherqual, econtext))
				{
					/*
					 * qualification was satisfied so we project and return
					 * the slot containing the result tuple using
					 * ExecProject().
					 */
					ENL1_printf("qualification succeeded, projecting tuple");

					return ExecProject(node->js.ps.ps_ProjInfo);
				}
				else
					InstrCountFiltered2(node, 1);
			}

			/*
			 * Otherwise just return to top of loop for a new outer tuple.
			 */
			continue;
		}

		/*
		 * at this point we have a new pair of inner and outer tuples so we
		 * test the inner and outer tuples to see if they satisfy the node's
		 * qualification.
		 *
		 * Only the joinquals determine MatchedOuter status, but all quals
		 * must pass to actually return the tuple.
		 */
		ENL1_printf("testing qualification");

		
		

		if (ExecQual(joinqual, econtext))
		{
			node->nl_MatchedOuter = true;

			/* In an antijoin, we never return a matched tuple */
			if (node->js.jointype == JOIN_ANTI)
			{
				node->nl_NeedNewOuter = true;
				continue;		/* return to top of loop */
			}

			/*
			 * If we only need to join to the first matching inner tuple, then
			 * consider returning this one, but after that continue with next
			 * outer tuple.
			 */
			if (node->js.single_match)
				node->nl_NeedNewOuter = true;

			if (otherqual == NULL || ExecQual(otherqual, econtext))
			{
				/*
				 * qualification was satisfied so we project and return the
				 * slot containing the result tuple using ExecProject().
				 */
				ENL1_printf("qualification succeeded, projecting tuple");

				return ExecProject(node->js.ps.ps_ProjInfo);
			}
			else;
				InstrCountFiltered2(node, 1);
		}
		else
			InstrCountFiltered1(node, 1);

		/*
		 * Tuple fails qual, so free per-tuple memory and try again.
		 */
		ResetExprContext(econtext);

		ENL1_printf("qualification failed, looping");
	}
}

猜你喜欢

转载自blog.csdn.net/zhoutianzi12/article/details/91902899
new