当前位置: 首页 > news >正文

Oracle Form - 文件夹数据块点击排序后只剩一行显示(已解决)

  • 问题现象

最近在工作中遇到一个诡异的问题:背景是我开发了一个主从结构的表单,而且主从块都使用了文件夹功能;问题现象是,在查询出结果后,点击主块的标题执行排序,主块突然变成了只显示一行

查看排序前后主块的last query发现异样:

图一为排序前主块last query的WHERE条件,year=2019是块属性里面设置的Where子句,year between 2017 and 2022是我为了方便观察在pre-query触发器里加的查询条件

图二为排序后,可以看到year=2019这一句没变,但是后一句变成了delivery_plan_header_id=34179,就是它直接导致主块只变成一行了,因为这个字段是主键

补充一句:这个现象只在查询后主块第一行没有关联的从块数据时发生

  • 检查过程

经过检查APPFLDR库,我找到了问题原因

首先简述一下排序的实现机制:1、安排好排序字段,顺序,升降序;2、给块设置一个临时的Default Where属性;3、执行查询;4、将块的Default Where属性复原

(参见APPFLDR库文件过程app_folder_drag_and_drop)

这里的第二步我分析其目的就是为了重新执行的查询条件和排序前执行的最后一次查询保持一致

这里设置的临时Default Where属性其内容为:

app_folder.base_where_clause || ' AND -1=-1 AND ' ||
app_folder.pending_where_clause || ' AND -2=-2'

在这里可以看到上图二中标志性的-1=-1和-2=-2,同时也推断出delivery_plan_header_id=34179即是当时app_folder.pending_where_clause的内容

进一步查看发现,这个pending_where_clause是在app_folder_ext_whr_cls过程中做初始赋值的:内容来源于system.last_query,从中截取WHERE到ORDER BY中间的内容

并且该过程还会将这个内容放入记录组folder_master_props.pending_where_clause里与当前块进行绑定

最后还会将一个全局变量global.folder_where_extracted标记为TRUE

这个变量大有来头:

1、在app_folder.event('PRE-QUERY')中,会直接令其为FALSE

2、在app_folder.event('POST-QUERY')中,会判断当它是FALSE时,执行app_folder_ext_whr_cls

3、app_folder.event('KEY-EXEQRY')中,只做了两件事:execute_query,和判断global.folder_where_extracted为FALSE时,执行app_folder_ext_whr_cls

另外,我又在app_folder.event('PRE-BLOCK')中发现,它调用的app_folder_get_instance_values过程,会用system.trigger_name去匹配出folder_master_props.pending_where_clause的内容存放至app_folder.pending_where_clause

至此问题就讲得通了

  • 问题原因

对于一个独立的文件夹数据块来说,执行查询时触发器的执行顺序是:

KEY-EXEQRY

        PRE-QUERY

        POST-QUERY

KEY-EXEQRY

这里没有对齐的原因是PRE-QUERY是从KEY-EXEQRY中断去执行的,PRE-QUERY只执行一次,POST-QUERY在每加载出一行记录后各执行一次,最后回到KEY-EXEQRY来

而如果这个数据块同时又是一个主数据块,它在自己的最后一行加载出来,执行一次POST-QUERY后,便会回到第一条记录,再跳到从块上执行关联查询

这时先触发主块的POST-BLOCK,接下来依次是从块的PRE-BLOCK、PRE-QUERY、POST-QUERY、POST-BLOCK,再又回到主块,触发PRE-BLOCK,中断结束,继续KEY-EXEQRY触发器

问题就发生在这个过程中:当从块没有数据时,其POST-QUERY就没有执行;而它的PRE-QUERY已将全局变量global.folder_where_extracted赋值为FALSE了,此时回到主块的KEY-EXEQRY,正是执行完execute_query,该判断这个参数的时候了,程序发现它是FALSE,当即执行app_folder_ext_whr_cls,然而此时的system.last_query是时方才从块的last query,结果就是张冠李戴了

前图二中的delivery_plan_header_id正是设置的主从块关系条件

  • 解决方法

方法一:主块不使用app_folder.event('KEY-EXEQRY')作为KEY-EXEQRY触发器,或者干脆不增加KEY-EXEQRY触发器

方法二:客制化app_folder.event('PRE-BLOCK'),即在取出app_folder.pending_where_clause内容后,举手之劳把global.folder_where_extracted赋值为TRUE

附程序单元:

1)程序包规格

PACKAGE bhsc_folder IS
  procedure event(trigger_name varchar2);
END;

2)程序包主体

PACKAGE BODY bhsc_folder IS
	PROCEDURE my_folder_get_instance_values (target_block varchar2) IS
	--
	-- Sets pointers and package globals for the proper folder block
	--
	  block_name      VARCHAR2(30);
	  function_mask   VARCHAR2(18);
	  item_name       VARCHAR2(30);
	  item_id         ITEM;
	  item_width      NUMBER;
	  item_prompt     VARCHAR2(80); 
	  item_x          NUMBER := null;
	  item_y          NUMBER := null;
	  folder_item_id  ITEM;
	  dummy           groupcolumn; --dummy colid to allow creation of the tab order column
	  pointers_set    BOOLEAN := FALSE;
	  rg_id 	  recordgroup;
	  rg_col_id       groupcolumn; 
	  errcode         NUMBER;
	  curr_block_id   BLOCK;
	BEGIN
	  app_folder_frd_stmt('Entering app_folder_get_instance_values. Target_block is '||target_block);
	  app_folder.master_props_id := find_group('folder_master_props');
	  if id_null(app_folder.master_props_id) then 
	    app_folder_set_static_handles;
	  end if;
	  
	  -- Check to see if this block exists in the master_props record group.  
	  -- If not, do nothing.
	  --
	  if (get_group_record_number('folder_master_props.folder_block', target_block)=0) then 
	    return;
	  end if;
	
	  -- 
	  -- Get the current slot in master properties, and the current object name, 
	  -- so that we can use them to check for a default folder
	  -- 
	  app_folder.current_slot := get_group_record_number('folder_master_props.folder_block', target_block);
	  if (app_folder.current_slot = 0) then 
	    message('FOLDER ERROR: Block not defined as folder block: ' || target_block);
	    for i in 1..get_group_row_count(app_folder.master_props_id) loop
	      message('row ' || to_char(i) || ': ' || get_group_char_cell('folder_master_props.prompt_block', i));
	    end loop;
	    return;
	  end if;
	
	  app_folder.curr_object :=
	    get_group_char_cell('folder_master_props.curr_object', app_folder.current_slot);  
	
	  --
	  -- Check to see if master/active record groups have already been created.  If not, 
	  -- check for a default folder, then create and populate the record groups.
	  -- 
	  app_folder.master_list_id := find_group('folderm_'||target_block);
	  if id_null(app_folder.master_list_id) then
	    --
	    -- Get the default folder id if there is one
	    -- 
	    app_folder.default_folder_id := app_folder_get_default_id; 
	    set_group_number_cell('folder_master_props.default_folder_id', app_folder.current_slot, app_folder.default_folder_id);
	    -- 
	    -- Call app_folder_create_groups to create and populate 
	    -- the master and active lists for this block
	    --
	    app_folder_create_groups(target_block);
	    pointers_set := TRUE;
	  end if;
	
	  if app_folder.folder_block != target_block then
	    block_name := target_block;
	    app_folder.folder_block := block_name;
	    app_folder.folder_block_id := find_block(block_name);
	    app_folder.folder_window := get_group_char_cell('folder_master_props.folder_window', app_folder.current_slot);
	    app_folder.folder_window_id := find_window(app_folder.folder_window);
	    app_folder.folder_canvas :=
	      get_group_char_cell('folder_master_props.folder_canvas', app_folder.current_slot);
	    app_folder.folder_tab_canvas :=
	      get_group_char_cell('folder_master_props.folder_tab_canvas', app_folder.current_slot);
	    app_folder.folder_content_canvas :=
	      get_group_char_cell('folder_master_props.folder_content_canvas', app_folder.current_slot);
	    app_folder.folder_fixed_canvas :=
	      get_group_char_cell('folder_master_props.folder_fixed_canvas', app_folder.current_slot);
	    app_folder.prompt_block := 
	      get_group_char_cell('folder_master_props.prompt_block', app_folder.current_slot);
	    app_folder.total_block := 
	      get_group_char_cell('folder_master_props.total_block', app_folder.current_slot);
	    app_folder.total_fields :=
	      get_group_number_cell('folder_master_props.total_fields', app_folder.current_slot);
	    app_folder.base_records_displayed :=
	      get_group_number_cell('folder_master_props.base_records_displayed', app_folder.current_slot);
	    app_folder.base_order_by := 
	      get_group_char_cell('folder_master_props.base_order_by', app_folder.current_slot);
	    app_folder.base_where_clause := 
	      get_group_char_cell('folder_master_props.base_where_clause', app_folder.current_slot);
	    --fnd_message.debug('Setting damage flag in GIV');
	    app_folder.damage_flag := 
	      (get_group_char_cell('folder_master_props.damage_flag', app_folder.current_slot) = 'Y');
	    app_folder.instantiated := 
	      (get_group_char_cell('folder_master_props.instantiated', app_folder.current_slot) = 'Y');
	    app_folder.tab_sorted := 
	      (get_group_char_cell('folder_master_props.tab_sorted', app_folder.current_slot) = 'Y');
	    app_folder.cut_column_flag := 
	      get_group_char_cell('folder_master_props.cut_column_flag', app_folder.current_slot);
	    app_folder.curr_folder_name := 
	      get_group_char_cell('folder_master_props.curr_folder_name', app_folder.current_slot);
	    app_folder.curr_folder_id :=
	      get_group_number_cell('folder_master_props.curr_folder_id', app_folder.current_slot);
	    app_folder.curr_autoquery_flag :=
	      get_group_char_cell('folder_master_props.curr_autoquery_flag', app_folder.current_slot);
	    app_folder.curr_owner_id :=          
	      get_group_number_cell('folder_master_props.curr_owner_id', app_folder.current_slot);
	    app_folder.curr_public_flag :=
	      get_group_char_cell('folder_master_props.curr_public_flag', app_folder.current_slot);
	    app_folder.curr_default_flag :=
	      get_group_char_cell('folder_master_props.curr_default_flag', app_folder.current_slot);
	    app_folder.curr_where_clause :=
	      get_group_char_cell('folder_master_props.curr_where_clause', app_folder.current_slot);
	    --
	    -- Moving this call to beginning of procedure, since we need the object name to 
	    -- determine whether the user has a default. 
	    --
	    --app_folder.curr_object :=
	      --get_group_char_cell('folder_master_props.curr_object', app_folder.current_slot);  
	    app_folder.pending_where_clause :=
	      get_group_char_cell('folder_master_props.pending_where_clause', app_folder.current_slot);
	    copy('TRUE', 'global.folder_query_extracted'); --added by yusuf 19-sept-2022
	    app_folder.developer_folder_id := 
	      get_group_number_cell('folder_master_props.developer_folder_id', app_folder.current_slot);
	    --
	    -- Set the master and active record group pointers if not just created.
	    --
	    if not pointers_set then 
	      -- app_folder.master_list_id was set at beginning of routine.
	      -- app_folder.master_list_id := find_group('folderm_'||block_name);
	      app_folder.master_name_id := find_column('folderm_'||block_name||'.name');  
	      app_folder.master_prompt_id := find_column('folderm_'||block_name||'.prompt'); 
	      --app_folder.master_active_flag_id := find_column('folderm_'||block_name||'.active_flag'); 
	      app_folder.master_width_id := find_column('folderm_'||block_name||'.width');
	      app_folder.master_allow_cut_flag_id := find_column('folderm_'||block_name||'.allow_cut_flag');
	      app_folder.master_rows := get_group_row_count(app_folder.master_list_id);
	      --
	      app_folder.active_list_id := find_group('foldera_'||block_name);
	      app_folder.active_name_id := find_column('foldera_'||block_name||'.name');  
	      app_folder.active_prompt_id := find_column('foldera_'||block_name||'.prompt'); 
	      app_folder.active_width_id := find_column('foldera_'||block_name||'.width');
	      app_folder.active_x_pos_id := find_column('foldera_'||block_name||'.x_pos');
	      app_folder.active_y_pos_id := find_column('foldera_'||block_name||'.y_pos');
	      app_folder.active_rows := get_group_row_count(app_folder.active_list_id);
	      -- 
	      -- Also reset default_folder_id
	      -- 
	      app_folder.default_folder_id := get_group_number_cell('folder_master_props.default_folder_id', app_folder.current_slot);
	    end if;
	    --
	    -- Set the function allowed flags from the function mask
	    --
	    function_mask := 
	      get_group_char_cell('folder_master_props.allowed_functions', app_folder.current_slot);  
	    app_folder.autoquery_allowed := (instr(function_mask, 'A') != 0);
	    app_folder.public_allowed    := (instr(function_mask, 'B') != 0);
	    app_folder.default_allowed   := (instr(function_mask, 'C') != 0);
	    app_folder.orderby_allowed := (instr(function_mask, 'D') != 0);
	    app_folder.open_allowed := (instr(function_mask, 'E') != 0);
	    app_folder.tools_allowed := (instr(function_mask, 'F') != 0);
	    app_folder.new_allowed := (instr(function_mask, 'G') != 0);
	    app_folder.save_allowed := (instr(function_mask, 'H') != 0);
	    app_folder.delete_allowed := (instr(function_mask, 'I') != 0);
	    app_folder.add_allowed := (instr(function_mask, 'J') != 0);
	    app_folder.cut_allowed := (instr(function_mask, 'K') != 0);
	    app_folder.swap_allowed := (instr(function_mask, 'L') != 0);
	    app_folder.bigger_allowed := (instr(function_mask, 'M') != 0);
	    app_folder.smaller_allowed := (instr(function_mask, 'N') != 0);
	    app_folder.autosize_allowed := (instr(function_mask, 'O') != 0);
	    app_folder.prompt_allowed := (instr(function_mask, 'P') != 0);
	    app_folder.contents_allowed := (instr(function_mask, 'Q') != 0);
	    app_folder.reset_allowed := (instr(function_mask, 'R') != 0);
	    --
	  end if;
	  app_folder_frd_stmt('Completed app_folder_get_instance_values.');
	END my_folder_get_instance_values;
  
  
  procedure event(trigger_name varchar2) is
  
  begin
  	if upper(trigger_name) = 'PRE-BLOCK' THEN
  	  my_folder_get_instance_values(name_in('system.trigger_block'));
  	ELSE
  	  app_folder_fldr_handler(trigger_name);
  	end if;
  end;
  
END;

3)触发器

bhsc_folder.event('PRE-BLOCK');

相关文章:

  • 【操作系统】面向真题学操作系统 —— 操作系统概述客观题
  • QT-子窗口关闭时,为什么不执行析构函数问题
  • 猿创征文| openGauss 数据库实战 主备高可用部署(主备部署模式)
  • 基于simulink的电气弹簧ES稳压控制模型仿真
  • Day759.Redis脑裂问题 -Redis 核心技术与实战
  • CSS高级篇——更多选择器 (selectors)
  • R语言(5) 折线图、散点图
  • 云原生之容器编排实践-SpringBoot应用以YAML描述文件部署pod到minikube
  • 【K8S】kubectl常用命令总结
  • 一文搞懂大数据入门之 Hadoop,HDFS,Hbase,Hive
  • FreeRTOS-实现任务调度器
  • 基于51单片机公交车到站指示灯设计
  • MySQL表的增删查改
  • 开关电源学习(一) MP2315S简介
  • String类详解(上)
  • 【跃迁之路】【699天】程序员高效学习方法论探索系列(实验阶段456-2019.1.19)...
  • 08.Android之View事件问题
  • 345-反转字符串中的元音字母
  • C# 免费离线人脸识别 2.0 Demo
  • github从入门到放弃(1)
  • iOS筛选菜单、分段选择器、导航栏、悬浮窗、转场动画、启动视频等源码
  • JavaScript函数式编程(一)
  • js
  • leetcode98. Validate Binary Search Tree
  • Magento 1.x 中文订单打印乱码
  • python学习笔记-类对象的信息
  • TypeScript迭代器
  • webpack入门学习手记(二)
  • - 概述 - 《设计模式(极简c++版)》
  • 给Prometheus造假数据的方法
  • 构建二叉树进行数值数组的去重及优化
  • 前端学习笔记之原型——一张图说明`prototype`和`__proto__`的区别
  • 浅析微信支付:申请退款、退款回调接口、查询退款
  • 我感觉这是史上最牛的防sql注入方法类
  • 写给高年级小学生看的《Bash 指南》
  • 学习HTTP相关知识笔记
  • 7行Python代码的人脸识别
  • ​ssh-keyscan命令--Linux命令应用大词典729个命令解读
  • #微信小程序:微信小程序常见的配置传值
  • (C语言)二分查找 超详细
  • (day 12)JavaScript学习笔记(数组3)
  • (Demo分享)利用原生JavaScript-随机数-实现做一个烟花案例
  • (动手学习深度学习)第13章 计算机视觉---图像增广与微调
  • (二)springcloud实战之config配置中心
  • (附源码)ssm高校社团管理系统 毕业设计 234162
  • (附源码)ssm考生评分系统 毕业设计 071114
  • (顺序)容器的好伴侣 --- 容器适配器
  • (一)ClickHouse 中的 `MaterializedMySQL` 数据库引擎的使用方法、设置、特性和限制。
  • (一)为什么要选择C++
  • (转载)Linux网络编程入门
  • (状压dp)uva 10817 Headmaster's Headache
  • @hook扩展分析
  • @Pointcut 使用
  • @拔赤:Web前端开发十日谈
  • [ Linux 长征路第五篇 ] make/Makefile Linux项目自动化创建工具