⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 subquerynode.java

📁 derby database source code.good for you.
💻 JAVA
📖 第 1 页 / 共 5 页
字号:
	 * @param dataDictionary	The DataDictionary to use for optimization	 * @param outerRows			The optimizer's estimate of the number of	 *							times this subquery will be executed.	 *	 * @return	Nothing	 *	 * @exception StandardException		Thrown on error	 */	public void optimize(DataDictionary dataDictionary, double outerRows) 					throws StandardException	{		/* RESOLVE - is there anything else that we need to do for this		 * node.		 */		/* Optimize the underlying result set */		resultSet = resultSet.optimize(dataDictionary, null, outerRows);	}	/**	 * Make any changes to the access paths, as decided by the optimizer.	 *	 * @exception StandardException		Thrown on error	 */	public void modifyAccessPaths() throws StandardException	{		resultSet = resultSet.modifyAccessPaths();	}	/**	 * Return the variant type for the underlying expression.	 * The variant type can be:	 *		VARIANT				- variant within a scan	 *							  (method calls and non-static field access)	 *		SCAN_INVARIANT		- invariant within a scan	 *							  (column references from outer tables)	 *		QUERY_INVARIANT		- invariant within the life of a query	 *							  (constant expressions)	 *	 * @return	The variant type for the underlying expression.	 *	 * @exception StandardException		Thrown on error	 */	protected int getOrderableVariantType() throws StandardException	{		/* 		 * If the subquery is variant, than return		 * VARIANT.  Otherwise, if we have an expression		 * subquery and no correlated CRs we are going		 * to materialize it, so it is QUERY_INVARIANT.	  	 * Otherwise, SCAN_INVARIANT.		 */		if (isInvariant())		{			if (!hasCorrelatedCRs() && 				(subqueryType == EXPRESSION_SUBQUERY))			{				return Qualifier.QUERY_INVARIANT;			}			else			{				return Qualifier.SCAN_INVARIANT;			}		}		else		{			return Qualifier.VARIANT;		}	}	/**	 * Do code generation for this subquery.	 *	 * @param expressionBuilder	The ExpressionClassBuilder for the class being built	 * @param mbex	The method the expression will go into	 *	 *	 * @exception StandardException		Thrown on error	 */	public void generateExpression(									ExpressionClassBuilder expressionBuilder,									MethodBuilder mbex)								throws StandardException	{		CompilerContext	cc = getCompilerContext();		String			resultSetString;		///////////////////////////////////////////////////////////////////////////		//		//	Subqueries should not appear in Filter expressions. We should get here		//	only if we're compiling a query. That means that our class builder		//	is an activation builder. If we ever allow subqueries in filters, we'll		//	have to revisit this code.		//		///////////////////////////////////////////////////////////////////////////				if (SanityManager.DEBUG)		{			SanityManager.ASSERT(expressionBuilder instanceof ActivationClassBuilder,				"Expecting an ActivationClassBuilder");		}		ActivationClassBuilder	acb = (ActivationClassBuilder) expressionBuilder;		/* Reuse generated code, where possible */		/* Generate the appropriate (Any or Once) ResultSet */		if (subqueryType == EXPRESSION_SUBQUERY)		{			resultSetString = "getOnceResultSet";		}		else		{			resultSetString = "getAnyResultSet";		}		// Get cost estimate for underlying subquery		CostEstimate costEstimate = resultSet.getFinalCostEstimate();		/* Generate a new method.  It's only used within the other		 * exprFuns, so it could be private. but since we don't		 * generate the right bytecodes to invoke private methods,		 * we just make it protected.  This generated class won't		 * have any subclasses, certainly! (nat 12/97)		 */		String subqueryTypeString =							getTypeCompiler().interfaceName();		MethodBuilder	mb = acb.newGeneratedFun(subqueryTypeString, Modifier.PROTECTED);		/* Declare the field to hold the suquery's ResultSet tree */		LocalField rsFieldLF = acb.newFieldDeclaration(Modifier.PRIVATE, ClassName.NoPutResultSet);		ResultSetNode subNode = null;		if (!isMaterializable())		{            MethodBuilder executeMB = acb.getExecuteMethod();			if (pushedNewPredicate && (! hasCorrelatedCRs()))			{				/* We try to materialize the subquery if it can fit in the memory.  We				 * evaluate the subquery first.  If the result set fits in the memory,				 * we replace the resultset with in-memory unions of row result sets.				 * We do this trick by replacing the child result with a new node --				 * MaterializeSubqueryNode, which essentially generates the suitable				 * code to materialize the subquery if possible.  This may have big				 * performance improvement.  See beetle 4373.				 */				if (SanityManager.DEBUG)				{					SanityManager.ASSERT(resultSet instanceof ProjectRestrictNode,						"resultSet expected to be a ProjectRestrictNode!");				}				subNode = ((ProjectRestrictNode) resultSet).getChildResult();				LocalField subRS = acb.newFieldDeclaration(Modifier.PRIVATE, ClassName.NoPutResultSet);				mb.getField(subRS);				mb.conditionalIfNull();				ResultSetNode materialSubNode = new MaterializeSubqueryNode(subRS);				// Propagate the resultSet's cost estimate to the new node.				materialSubNode.costEstimate = resultSet.getFinalCostEstimate();				((ProjectRestrictNode) resultSet).setChildResult(materialSubNode);				/* Evaluate subquery resultset here first.  Next time when we come to				 * this subquery it may be replaced by a bunch of unions of rows.				 */				subNode.generate(acb, mb);				mb.startElseCode();				mb.getField(subRS);				mb.completeConditional();						mb.setField(subRS);                executeMB.pushNull( ClassName.NoPutResultSet);                executeMB.setField(subRS);			}            executeMB.pushNull( ClassName.NoPutResultSet);            executeMB.setField(rsFieldLF); 			// now we fill in the body of the conditional			mb.getField(rsFieldLF);			mb.conditionalIfNull();		}		acb.pushGetResultSetFactoryExpression(mb);		// start of args		int nargs;		/* Inside here is where subquery could already have been materialized. 4373		 */		resultSet.generate(acb, mb);		/* Get the next ResultSet #, so that we can number the subquery's 		 * empty row ResultColumnList and Once/Any ResultSet.		 */		int subqResultSetNumber = cc.getNextResultSetNumber();		/* We will be reusing the RCL from the subquery's ResultSet for the 		 * empty row function.  We need to reset the resultSetNumber in the		 * RCL, before we generate that function.  Now that we've called		 * generate() on the subquery's ResultSet, we can reset that		 * resultSetNumber.		 */		resultSet.getResultColumns().setResultSetNumber(subqResultSetNumber);		acb.pushThisAsActivation(mb);		/* Generate code for empty row */		resultSet.getResultColumns().generateNulls(acb, mb);		/*		 *	arg1: suqueryExpress - Expression for subquery's		 *		  ResultSet		 *  arg2: Activation		 *  arg3: Method to generate Row with null(s) if subquery		 *		  Result Set is empty		 */		if (subqueryType == EXPRESSION_SUBQUERY)		{			int cardinalityCheck;			/* No need to do sort if subquery began life as a distinct expression subquery.			 * (We simply check for a single unique value at execution time.)			 * No need for cardinality check if we know that underlying			 * ResultSet can contain at most 1 row.			 * RESOLVE - Not necessary if we know we			 * are getting a single row because of a unique index.			 */			if (distinctExpression)			{				cardinalityCheck = OnceResultSet.UNIQUE_CARDINALITY_CHECK;			}			else if (resultSet.returnsAtMostOneRow())			{				cardinalityCheck = OnceResultSet.NO_CARDINALITY_CHECK;			}			else			{				cardinalityCheck = OnceResultSet.DO_CARDINALITY_CHECK;			}			/*  arg4: int - whether or not cardinality check is required			 *				DO_CARDINALITY_CHECK - required			 *				NO_CARDINALITY_CHECK - not required			 *				UNIQUE_CARDINALITY_CHECK - verify single			 *											unique value			 */			mb.push(cardinalityCheck);			nargs = 9;		} else {			nargs = 8;		}		mb.push(subqResultSetNumber);		mb.push(subqueryNumber);		mb.push(pointOfAttachment);		mb.push(costEstimate.rowCount());		mb.push(costEstimate.getEstimatedCost());		mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, resultSetString, ClassName.NoPutResultSet, nargs);		/* Fill in the body of the method		 * generates the following.		 * (NOTE: the close() method only generated for		 * materialized subqueries.  All other subqueries		 * closed by top result set in the query.):		 * 		 *	NoPutResultSet	rsFieldX;		 *	{		 *		<Datatype interface> col;		 *		ExecRow r;		 *		rsFieldX = (rsFieldX == null) ? outerRSCall() : rsFieldX; // <== NONmaterialized specific		 *		rsFieldX.openCore();		 *		r = rsFieldX.getNextRowCore();		 *		col = (<Datatype interface>) r.getColumn(1);		 *		return col;		 *	}		 *		 * MATERIALIZED:		 *	NoPutResultSet	rsFieldX;		 *	{		 *		<Datatype interface> col;		 *		ExecRow r;		 *		rsFieldX = outerRSCall();		 *		rsFieldX.openCore();		 *		r = rsFieldX.getNextRowCore();		 *		col = (<Datatype interface>) r.getColumn(1);		 *		rsFieldX.close();								// <== materialized specific		 *		return col;		 *	}		 * and adds it to exprFun		 */		/* Generate the declarations */ // PUSHCOMPILE		//VariableDeclaration colVar = mb.addVariableDeclaration(subqueryTypeString);		//VariableDeclaration rVar   = mb.addVariableDeclaration(ClassName.ExecRow);		if (!isMaterializable())		{			/* put it back			 */			if (pushedNewPredicate && (! hasCorrelatedCRs()))				((ProjectRestrictNode) resultSet).setChildResult(subNode);			// now we fill in the body of the conditional			mb.startElseCode();			  mb.getField(rsFieldLF);			mb.completeConditional();		}				mb.setField(rsFieldLF);		/* rs.openCore() */		mb.getField(rsFieldLF);		mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, "openCore", "void", 0);		/* r = rs.next() */		mb.getField(rsFieldLF);		mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, "getNextRowCore", ClassName.ExecRow, 0);		//mb.putVariable(rVar);		//mb.endStatement();		/* col = (<Datatype interface>) r.getColumn(1) */		//mb.getVariable(rVar);		mb.push(1); // both the Row interface and columnId are 1-based		mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.Row, "getColumn", ClassName.DataValueDescriptor, 1);		mb.cast(subqueryTypeString);		//mb.putVariable(colVar);		//mb.endStatement();		/* Only generate the close() method for materialized		 * subqueries.  All others will be closed when the		 * close() method is called on the top ResultSet.		 */		if (isMaterializable())		{			/* rs.close() */			mb.getField(rsFieldLF);			mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.ResultSet, "close", "void", 0);		}		/* return col */		//mb.getVariable(colVar);		mb.methodReturn();		mb.complete();		/*		** If we have an expression subquery, then we		** can materialize it if it has no correlated		** column references and is invariant.		*/		if (isMaterializable())		{			LocalField lf = generateMaterialization(acb, mb, subqueryTypeString);			mbex.getField(lf);		} else {			/* Generate the call to the new method */			mbex.pushThis();			mbex.callMethod(VMOpcode.INVOKEVIRTUAL, (String) null, mb.getName(), subqueryTypeString, 0);		}	}	/*	** Materialize the subquery in question.  Given the expression	** that represents the subquery, this returns fieldX where	** fieldX is set up as follows:	**	** private ... fieldX	**	** execute()	** {	**	fieldX = <subqueryExpression>	**	...	** }	**	** So we wind up evaluating the subquery when we start	** execution.  Obviously, it is absolutely necessary that	** the subquery is invariant and has no correlations	** for this to work.	**	** Ideally we wouldn't evaluate the expression subquery	** until we know we need to, but because we are marking	** this expression subquery as pushable, we must evaluate	** it up front because it might wind up as a qualification,	** and we cannot execute a subquery in the store as a	** qualification because the store executes qualifications	** while holding a latch.  	**	** @param acb	** @param type 	** @param subqueryExpression	*/	private LocalField generateMaterialization(			ActivationClassBuilder	acb,			MethodBuilder mbsq,			String 			type)	{		MethodBuilder mb = acb.executeMethod;		// declare field		LocalField field = acb.newFieldDeclaration(Modifier.PRIVATE, type);		/* Generate the call to the new method */		mb.pushThis();		mb.callMethod(VMOpcode.INVOKEVIRTUAL, (String) null, mbsq.getName(), type, 0);		// generate: field = value (value is on stack)		mb.setField(field);		return 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -