// 递归函数,得一个节点的集合,外面doSearch调该函数 // parameter: // nodeRoot 当前根节点 // resultSet 结果集。返回时不能确保结果集已经排序。需要看resultset.Sorted成员 // return: // -1 出错 // -6 无权限 // 0 成功 public int DoQuery( SessionInfo sessioninfo, string strOutputStyle, XmlElement nodeRoot, ref DpResultSet resultSet, ChannelHandle handle, // Delegate_isConnected isConnected, out string strError) { DateTime start_time = DateTime.Now; Debug.WriteLine("Begin DoQuery()"); try { strError = ""; if (nodeRoot == null) { strError = "DoQuery() nodeRoot参数不能为null。"; return -1; } #if NO if (resultSet == null) { strError = "DoQuery() resultSet参数不能为null。"; return -1; } #endif if (resultSet != null) { // 先清空一下 resultSet.Clear(); } // 到item时不再继续递归 if (nodeRoot.Name == "item") { if (resultSet == null) resultSet = sessioninfo.NewResultSet(); // 延迟创建 // return: // -1 出错 // -6 无足够的权限 // 0 成功 return doItem( sessioninfo, strOutputStyle, nodeRoot, ref resultSet, handle, // isConnected, out strError); } //如果为扩展节点,则不递归 if (nodeRoot.Name == "operator" || nodeRoot.Name == "lang") { return 0; } //将正常顺序变成逆波兰表序 ArrayList rpn; // return: // -1 出错 例如:括号不匹配;找不到某操作符的优先级 // 0 可用节点数为 0。等于没有任何可检索的必要 // 1 成功 int nRet = Infix2RPN(nodeRoot, out rpn, out strError); if (nRet == -1) { strError = "逆波兰表错误:" + strError; return -1; } if (nRet == 0) return -1; //属于正常情况 if (rpn.Count == 0) return 0; // return: // -1 出错 // -6 无足够的权限 // 0 成功 nRet = ProceedRPN( sessioninfo, strOutputStyle, rpn, ref resultSet, handle, // isConnected, out strError); if (nRet <= -1) return nRet; return 0; } finally { TimeSpan delta = DateTime.Now - start_time; Debug.WriteLine("End DoQuery() 耗时 " + delta.ToString()); } }
// 运算逆波兰表,得到结果集 // parameter: // rpn 逆波兰表 // resultSet 结果集 // return: // 0 成功 // -1 出错 原因可能如下: // 1)rpn参数为null // 2)oResultSet参数为null // 3)栈里的某成员出错(node和result都为null) // 4)从栈中pop()或peek()元素时,出现栈空 // 5)pop的类型,不是实际存在的类型 // 6)通过一个节点,得到结果集,即调DoQuery()函数出错 // 7)做运算时,调DpResultSetManager.Merge()函数出错 // 8)最后栈里的元素多于1,则逆波兰表出错 // 9)最后结果集为空 // -6 无足够的权限 public int ProceedRPN( SessionInfo sessioninfo, string strOutputStyle, ArrayList rpn, ref DpResultSet resultSet, ChannelHandle handle, // Delegate_isConnected isConnected, out string strError) { DateTime start_time = DateTime.Now; Debug.WriteLine("Begin ProceedRPN()"); try { strError = ""; //???要搞清楚用不用清空 //应该清空,后面的运算使用的结果集是堆栈变量,最后把运算结果拷贝到该结果集 //DoQuery处,也应该先清空 //doItem处,一进去先清空,但再对数据库循环检索时,千万不清空 if (resultSet != null) resultSet.Clear(); if (rpn == null) { strError = "rpn不能为null"; return -1; } #if NO if (resultSet == null) { strError = "resultSet不能为null"; return -1; } #endif if (rpn.Count == 0) return 0; int ret; // 声明栈,ReversePolishStack栈是自定义的类 // 决定用一个栈做运算,如果遇到遇到操作数,就直接push到栈里 // 遇到操作符,如果是双目,从栈里pop两项,进行运算 // 注意SUB运算是,用后一次pop的对象减前一次pop的对象 // // oReversePolandStack的成员为ReversePolishItem, // ReversePolishItem是一个复杂对象, // 包含m_int(类型),m_node(节点),m_resultSet. // 实际运用中,m_node和m_resultSet只有一项值有效,另一顶是null // m_int用于判断哪个值有效, // 0表示node有效,1表示resultSet有效 ReversePolishStack oReversePolandStack = new ReversePolishStack(); //做循环 for (int i = 0; i < rpn.Count; i++) { XmlElement node = (XmlElement)rpn[i]; if (node.Name != "operator") //操作数直接push到栈里 { oReversePolandStack.PushNode(node); } else { string strOpreator = DomUtil.GetAttr(node, "value"); #if NO //三个输出用于输入的参数,因为是指针,所以不用out DpResultSet oTargetLeft = sessioninfo.NewResultSet(); // new DpResultSet(); DpResultSet oTargetMiddle = sessioninfo.NewResultSet(); // new DpResultSet(); DpResultSet oTargetRight = sessioninfo.NewResultSet(); // new DpResultSet(); #endif //做一个两个成员的ArrayList, //成员类型为DpResultSet, //存放从栈里pop出的(如果是node,需要进行计算)的结果集 List<DpResultSet> oSource = new List<DpResultSet>(); oSource.Add(sessioninfo.NewResultSet()); // new DpResultSet() oSource.Add(sessioninfo.NewResultSet()); // new DpResultSet() try { for (int j = 0; j < 2; j++) { //类型为-1,表示node和resultSet都为null,出现错误 if (oReversePolandStack.PeekType() == -1) { strError = strOpreator + "时,PeekType()等于-1,则表示两项都是null,出错,返回-1<br/>"; return -1; } //表示放得是node if (oReversePolandStack.PeekType() == 0) { XmlElement nodePop; nodePop = oReversePolandStack.PopNode(); if (nodePop == null) { strError = "nodePop不为又能为null"; return -1; } DpResultSet temp = oSource[j]; // return: // -1 出错 // -6 无权限 // 0 成功 ret = this.DoQuery( sessioninfo, strOutputStyle, nodePop, ref temp, handle, // isConnected, out strError); if (ret <= -1) return ret; if (temp != oSource[j]) { // 2014/3/11 if (oSource[j] != null) oSource[j].Close(); oSource[j] = temp; } } else { DpResultSet temp = oReversePolandStack.PopResultSet(); Debug.Assert(temp != oSource[j], ""); // 2014/3/11 if (oSource[j] != null) oSource[j].Close(); oSource[j] = temp; if (oSource[j] == null) { strError = "PopResultSet() return null"; return -1; } } } } catch (StackUnderflowException /*ex*/) { // 2008/12/4 string strOutXml = ""; if (node.ParentNode != null) { int nRet = DomUtil.GetIndentXml(node.ParentNode.OuterXml, out strOutXml, out strError); } strError = strOpreator + " 是二元操作符,它缺乏操作数。"; if (String.IsNullOrEmpty(strOutXml) == false) strError += "\r\n" + strOutXml; // strError = "StackUnderflowException :" + ex.Message; return -1; } // string strDebugInfo; //OR,AND,SUB运算都是调的DpResultSetManager.Merge()函数, //注意参数的使用 if (strOpreator == "OR") { bool bOutputKeyCount = StringUtil.IsInList("keycount", strOutputStyle); bool bOutputKeyID = StringUtil.IsInList("keyid", strOutputStyle); DpResultSet left = oSource[1]; DpResultSet right = oSource[0]; #if DEBUG Debug.Assert(left.IsClosed == false, ""); Debug.Assert(right.IsClosed == false, ""); #endif { // 直接相加 if (left.Count == 0) { oReversePolandStack.PushResultSet( right ); // 2014/3/11 Debug.Assert(left != right, ""); left.Close(); } else if (right.Count == 0) { oReversePolandStack.PushResultSet( left ); // 2014/3/11 Debug.Assert(left != right, ""); right.Close(); } else { if (EnsureSorted(left, handle, out strError) == -1) return -1; if (EnsureSorted(right, handle, out strError) == -1) return -1; // return: // -1 出错 // 0 没有交叉部分 // 1 有交叉部分 ret = DpResultSetManager.IsCross(left, right, out strError); if (ret == -1) return -1; if (ret == 0) { DpResultSet left_save = left; // 注意:函数执行过程,可能交换 left 和 right。也就是说返回后, left == right ret = DpResultSetManager.AddResults(ref left, right, out strError); if (ret == -1) return -1; oReversePolandStack.PushResultSet( left ); // 2014/3/11 if (left != right) { Debug.Assert(left_save == left, ""); right.Close(); } else { Debug.Assert(left_save != left, ""); left_save.Close(); } } else { if (left.Asc != right.Asc) { right.Asc = left.Asc; right.Sorted = false; } if (EnsureSorted(left, handle, out strError) == -1) return -1; if (EnsureSorted(right, handle, out strError) == -1) return -1; { DpResultSet oTargetMiddle = sessioninfo.NewResultSet(); // new DpResultSet(); StringBuilder debugInfo = null; ret = DpResultSetManager.Merge(LogicOper.OR, left, right, strOutputStyle, null, oTargetMiddle, null, // false, querystop, handle, ref debugInfo, out strError); if (ret == -1) return -1; oReversePolandStack.PushResultSet(oTargetMiddle); // 2014/3/11 Debug.Assert(left != oTargetMiddle, ""); Debug.Assert(right != oTargetMiddle, ""); left.Close(); right.Close(); } } } } continue; } if (strOpreator == "AND") { DpResultSet left = oSource[1]; DpResultSet right = oSource[0]; #if DEBUG Debug.Assert(left.IsClosed == false, ""); Debug.Assert(right.IsClosed == false, ""); #endif if (left.Asc != right.Asc) { right.Asc = left.Asc; right.Sorted = false; } if (EnsureSorted(left, handle, out strError) == -1) return -1; if (EnsureSorted(right, handle, out strError) == -1) return -1; // 优化 if (left.Count == 0) { oReversePolandStack.PushResultSet( left ); // 2014/3/11 Debug.Assert(left != right, ""); right.Close(); } else if (right.Count == 0) { oReversePolandStack.PushResultSet( right ); // 2014/3/11 Debug.Assert(left != right, ""); left.Close(); } else { DpResultSet oTargetMiddle = sessioninfo.NewResultSet(); // new DpResultSet(); StringBuilder debugInfo = null; ret = DpResultSetManager.Merge(LogicOper.AND, left, right, strOutputStyle, null, //oTargetLeft oTargetMiddle, null, //oTargetRight // false, querystop, handle, ref debugInfo, out strError); if (ret == -1) return -1; oReversePolandStack.PushResultSet(oTargetMiddle); // 2014/3/11 Debug.Assert(left != oTargetMiddle, ""); Debug.Assert(right != oTargetMiddle, ""); left.Close(); right.Close(); } continue; } if (strOpreator == "SUB") { //因为使用从栈里pop,所以第0个是后面的,第1个是前面的 DpResultSet left = oSource[1]; DpResultSet right = oSource[0]; #if DEBUG Debug.Assert(left.IsClosed == false, ""); Debug.Assert(right.IsClosed == false, ""); #endif if (left.Asc != right.Asc) { right.Asc = left.Asc; right.Sorted = false; } if (EnsureSorted(left, handle, out strError) == -1) return -1; if (EnsureSorted(right, handle, out strError) == -1) return -1; // 优化 if (left.Count == 0) { oReversePolandStack.PushResultSet( left ); // 2014/3/11 Debug.Assert(left != right, ""); right.Close(); } else if (right.Count == 0) { oReversePolandStack.PushResultSet( left ); // 2014/3/11 Debug.Assert(left != right, ""); right.Close(); } else { DpResultSet oTargetLeft = sessioninfo.NewResultSet(); // new DpResultSet(); StringBuilder debugInfo = null; ret = DpResultSetManager.Merge(LogicOper.SUB, left, right, strOutputStyle, oTargetLeft, null, //oTargetMiddle null, //oTargetRight // false, querystop, handle, ref debugInfo, out strError); if (ret == -1) { return -1; } oReversePolandStack.PushResultSet(oTargetLeft); // 2014/3/11 Debug.Assert(left != oTargetLeft, ""); Debug.Assert(right != oTargetLeft, ""); left.Close(); right.Close(); } continue; } } } if (oReversePolandStack.Count > 1) { strError = "逆波兰出错"; return -1; } try { int nTemp = oReversePolandStack.PeekType(); //如果类型为0,表示存放的是节点 if (nTemp == 0) { XmlElement node = oReversePolandStack.PopNode(); // return: // -1 出错 // -6 无权限 // 0 成功 ret = this.DoQuery( sessioninfo, strOutputStyle, node, ref resultSet, handle, // isConnected, out strError); if (ret <= -1) return ret; } else if (nTemp == 1) { // 调DpResultSet的copy函数 // TODO: 测算这个Copy所花费的时间。 // resultSet.Copy((DpResultSet)(oReversePolandStack.PopResultSet())); resultSet = (DpResultSet)(oReversePolandStack.PopResultSet()); } else { strError = "oReversePolandStack的类型不可能为" + Convert.ToString(nTemp); return -1; } } catch (StackUnderflowException) { strError = "peek或pop时,抛出StackUnderflowException异常"; return -1; } //最后结果集为null,返回出错 if (resultSet == null) { strError = "运算结束后PopResultSet为null" + Convert.ToString(oReversePolandStack.PeekType()); return -1; } return 0; } finally { TimeSpan delta = DateTime.Now - start_time; Debug.WriteLine("End ProceedRPN() 耗时 " + delta.ToString()); } }
// 检索单元item的信息,对库进行检索 // parameter: // nodeItem item节点 // resultSet 结果集。返回时不能确保结果集已经排序。需要看resultset.Sorted成员 // 传进结果集,????????每次清空,既然每次清空,那还不如返回一个结果集呢 // isConnected 是否连接 // strError out参数,返回出错信息 // return: // -1 出错 // -6 无足够的权限 // 0 成功 public int doItem( SessionInfo sessioninfo, string strOutputStyle, XmlElement nodeItem, ref DpResultSet resultSet, ChannelHandle handle, // Delegate_isConnected isConnected, out string strError) { strError = ""; if (nodeItem == null) { strError = "doItem() nodeItem参数为null."; return -1; } if (resultSet == null) { strError = "doItem() oResult参数为null."; return -1; } string strResultSetName = nodeItem.GetAttribute("resultset"); if (string.IsNullOrEmpty(strResultSetName) == false) { resultSet.Close(); resultSet = null; DpResultSet source = null; if (KernelApplication.IsGlobalResultSetName(strResultSetName) == true) { source = this.m_dbColl.KernelApplication.ResultSets.GetResultSet(strResultSetName.Substring(1), false); } else { source = sessioninfo.GetResultSet(strResultSetName, false); } if (source == null) { strError = "没有找到名为 '" + strResultSetName + "' 的结果集对象"; return -1; } resultSet = source.Clone("handle"); resultSet.ReadOnly = true; return 0; } //先清空一下 resultSet.Clear(); int nRet; //调processRelation对检索单元的成员检查是否存在矛盾 //如果返回0,则可能对item的成员进行了修改,所以后面重新提取内容 nRet = ProcessRelation(nodeItem); if (nRet == -1) { // strError = "doItem()里调processRelation出错"; strError = "检索式局部有错: " + nodeItem.OuterXml; return -1; } // 根据nodeItem得到检索信息 string strTarget; string strWord; string strMatch; string strRelation; string strDataType; string strIdOrder; string strKeyOrder; string strOrderBy; string strHint = ""; int nMaxCount; nRet = QueryUtil.GetSearchInfo(nodeItem, strOutputStyle, out strTarget, out strWord, out strMatch, out strRelation, out strDataType, out strIdOrder, out strKeyOrder, out strOrderBy, out nMaxCount, out strHint, out strError); if (nRet == -1) return -1; bool bSearched = false; bool bNeedSort = false; bool bFirst = StringUtil.IsInList("first", strHint); // 是否为 命中则停止继续检索 // 将 target 以 ; 号分成多个库 string[] aDatabase = strTarget.Split(new Char[] { ';' }); foreach (string strOneDatabase in aDatabase) { if (strOneDatabase == "") continue; string strDbName; string strTableList; // 拆分库名与途径 nRet = DatabaseUtil.SplitToDbNameAndForm(strOneDatabase, out strDbName, out strTableList, out strError); if (nRet == -1) return -1; // 得到库 Database db = m_dbColl.GetDatabase(strDbName); if (db == null) { strError = "未找到'" + strDbName + "'库"; return -1; } // 2009/7/19 if (db.InRebuildingKey == true) { strError = "数据库 '" + db.GetCaption(null) + "' 正处在重建检索点状态,不能进行检索..."; return -1; } string strTempRecordPath = db.GetCaption("zh-CN") + "/" + "record"; string strExistRights = ""; bool bHasRight = this.m_oUser.HasRights(strTempRecordPath, ResType.Record, "read", out strExistRights); if (bHasRight == false) { strError = "您的帐户名为'" + m_oUser.Name + "'" + ",对'" + strDbName + "'" + "数据库中的记录没有'读(read)'权限,目前的权限为'" + strExistRights + "'。"; return -6; } SearchItem searchItem = new SearchItem(); searchItem.TargetTables = strTableList; searchItem.Word = strWord; searchItem.Match = strMatch; searchItem.Relation = strRelation; searchItem.DataType = strDataType; searchItem.IdOrder = strIdOrder; searchItem.KeyOrder = strKeyOrder; searchItem.OrderBy = strOrderBy; searchItem.MaxCount = nMaxCount; // 注: SearchByUnion不清空resultSet,从而使多个库的结果集放在一起 string strWarningInfo = ""; // -1 出错 // 0 成功 // 1 成功,但resultset需要再行排序一次 nRet = db.SearchByUnion( strOutputStyle, searchItem, handle, // isConnected, resultSet, this.m_nWarningLevel, out strError, out strWarningInfo); if (nRet == -1) return -1; bSearched = true; if (nRet == 1) bNeedSort = true; if (nRet >= 1 && bFirst == true) break; } // 2010/5/17 if (bSearched == true) { // 2010/5/11 resultSet.EnsureCreateIndex(); // 确保创建了索引 // 排序 // TODO: 其实可以使用EnsureSorted()函数 if (bNeedSort == true) { if (DoSort(resultSet, handle/*isConnected*/) == true) { strError = "前端中断"; return -1; } } // TODO: 也可以延迟排序,本函数返回一个值表希望排序。等到最后不得不排序时候再排序最好了 //resultSet.RemoveDup(); } return 0; }