从Oracle迁移到PostgreSQL时,大多数开发人员会询问在PostgreSQL中处理全局关联数组中可用的选项。如果需要在Exception块中访问变量,可能会变得很有挑战性。为避免开发人员在执行从Oracle到PL / SQL到PL / SQL的转换时发现困难,我们正在撰写此博客文章,以演示可用的解决方法,而无需进行太多额外的编程工作。
顺便说一句,阅读此博客文章后要注意的事实是,您可以在迁移或代码转换期间在PostgreSQL中观察到的一些功能,而无需使用PostgreSQL的其他企业许可证(这可以创建供应商锁定) )。
在转换为企业许可之前,请向我们询问使用社区PostgreSQL(开源)的可能性。 🙂
在开始解决方法之前,让我们了解什么是关联数组。在编程语言中,关联数组可以称为地图或字典。关联数组是(键,值)对的集合,其中键与值关联。键和值之间的这种关联可以被称为映射。键可以是文本或数字类型,可以映射到任何值类型。
PostgreSQL中的PL / pgSQL允许我们将变量声明为ARRAY类型。此数组可以是基本类型,也可以是自定义类型。例如,如果要存储PINCODE值列表,则可以将变量声明为v_pincode INT []。声明此变量后,便可以将表/视图/函数中的所有固定码值加载到此数组中。
我们还可以使用一组固定的Pincode值来初始化v_pincode数组类型。这里,v_pincode包含所有值,我们可以通过提供索引来获取特定州的pincode值。这意味着,如果要访问第一状态密码,则可以使用v_pincode [1]访问该值。如果要访问3rd状态的pincode值,则必须使用v_pincode [3]传递索引值3。
postgres =>创建或替换功能process_orders()以$ DECLARE返回BOOL-初始化静态密码v_pincode INT [] = ARRAY [123456,123457,123458,123459];开始发出通知'第一状态密码%',v_pincode [1];引发通知'第三状态密码%',v_pincode [3];返回true;结尾; $ LANGUAGE PLPGSQL;创建功能
我们得到了预期的结果。但是,此代码有一些限制,因为我们无法基于它们的键来获取值。例如,使用其索引获取密码(第一个和第三个元素)。如果我们能够基于它们的密钥访问相同的密码,那么查找将更加强大。那么,如何满足这一要求呢?让我们进一步讨论该方法。
得益于PostgreSQL丰富的数据类型,例如hstore或json,可以利用它们来执行此类映射。
创建或替换功能process_orders()以$ DECLARE返回BOOL-初始化静态密码v_pincode JSON =' {" CA&#34 ;: 123456," AZ&#34 ;: 123457,&#34 ; OH&#34 ;:" 123458&#34 ;," CO&#34 ;: 123459}&#39 ;;开始发出通知' CA状态密码%&#39,v_pincode->' CA&#39 ;;引发通知' OH状态密码%&#39 ;, v_pincode->' OH&#39 ;;返回true;结尾; $ LANGUAGE PLPGSQL;
现在,我们可以在我们的PL / pgSQL代码中使用键进行查找。因此,通过使用json类型而不是ARRAY,我们可以实现关联数组的概念。
上面演示的json方法似乎是完美的,但是它不能解决全局或会话级关联数组的问题。这意味着不能使用在同一会话中运行的另一个函数来访问相同的关联数组。这是因为缺少全局变量或全局数组。
在函数之间传递相同的值。但是,参数列表可能变得庞大,难以管理或调试。
将其存储在表中并通过从表中进行选择来访问元素。这可能是沉重的开销。
使用set_config()方法,该方法将对象设置为会话级别,然后从current_setting()中读取对象。
如果设置了任何值,则异常块将无法查看已配置的设置。在执行从Oracle到PostgreSQL的转换时可能会变得充满挑战,在Exception块中编写了大量的逻辑。当我们不在异常块中访问任何全局变量时,可能会很棒。我们将在未来的博客文章中对此进行详细讨论。
通过这种方法,我们应该能够跨异常块和非异常块访问全局变量。
前四种方法似乎很简单,但有其自身的局限性。但是使用另一种语言的会话上下文的最后一种方法很有趣,我们将对此进行进一步讨论。
众所周知,PostgreSQL支持许多受信任的过程语言,例如PLPerl,PLPython,PLTCL,PLv8等。所有这些受信任的语言保证了用该语言编写的程序代码将不会访问底层的物理文件。在所有这些编程语言中,我们将选择一种简单,安全且功能强大的语言称为tickle(PLTCL)。
TCL语言确实支持关联数组概念,我们将以全局方式利用此功能。这将为使用键的值查找提供更大的灵活性。让我们看下面的示例代码,看看如何用痒痒(TCL)声明全局变量。
TCL说明第一步,使用以下TCL代码声明全局变量(名称空间)。
$ tclsh%#这里,arr_ptr是一个指向命名空间/全局变量" pincodes"%upvar 0 :::" pincodes"的指针。 arr_ptr 现在,让我们向该名称空间(或全局变量)添加一个密码代码值。 通过上面创建的简单示例,我们了解了如何声明全局变量并使用TCL存储值。 为了实现全局关联数组的功能,让我们在PLTCL中嵌入相同的代码,如以下步骤所示。 步骤2:使用PLTCL创建一个函数以声明全局关联数组并设置一个值。 postgres => 创建或替换功能pltcl_set(TEXT,TEXT,TEXT)返回无效的$ upvar 0 :: $ 1 arr_ptrset arr_ptr($ 2)$ 3 $语言PLTCL;创建功能 步骤3:使用PLTCL创建一个函数,以获取映射到键的值。
postgres =>创建或替换功能pltcl_get(TEXT,TEXT)以$ upvar 0 :: $ 1返回arr_ptrset arr_ptr($ 2)$
如上例所示,我们能够从全局的TCL上下文中获取数据。这意味着,我们能够从一个语句中设置密码(使用pltctl_set()),并能够从另一条语句中访问其值(使用pltcl_get())。
什么是没有迭代器的数组,对吗?让我们利用相同的TCL代码并创建另一个遍历全局数组的函数。
postgres =>创建或替换功能pltcl_itr(TEXT)返回表(键TEXT,值TEXT)AS $ upvar 0 :: $ 1 foreach i [数组名称arr_ptr] {return_next [列表键$ i值[set arr_ptr($ i)]]} $语言PLTCL;创建函数
现在,让我们向“ pincodes”全局数组中添加更多条目,并进行迭代测试。
postgres => SELECT pltcl_set(' pincodes',' AZ',' 123457'); pltcl_set -----------((1 row)postgres =&gt ; SELECT pltcl_set(' pincodes',' OH',' 123458'); pltcl_set -----------((1 row)postgres =&gt ; SELECT pltcl_set(' pincodes',' CO',' 123459'); pltcl_set -----------(1行)
让我们使用迭代器功能从全局数组中获取所有可用密码的列表,如下面的块所示。
postgres => SELECT * FROM pltcl_itr(&pincodes');键|值----- + -------- CA | 123456CO | 123459OH | 123458AZ | 123457(4行)
如上所示,该迭代器实际上正在帮助迭代全局关联数组。我们可以在同一会话的多个函数中使用这些值。
PostgreSQL在以多种语言编写代码方面提供了很大的灵活性,最终使我们能够继承其他编程语言的功能。正如您在本博文中看到的那样,我们利用了TCL的功能,并且能够实现全局关联数组,该数组仅在Oracle等专有数据库中可用。
当您从Oracle迁移到PostgreSQL时,我们可能会遇到类似的情况,其中程序包正在使用全局关联数组。借助PLTCL或其他安全的解释器语言,我们可以轻松地在PostgreSQL中实现此功能。
在执行向PostgreSQL的迁移时,您是否阅读了有关外部数据包装程序的角色的博客文章?订阅我们的博客文章,以了解有关向PostgreSQL迁移的最新文章的最新信息。想迁移到开源PostgreSQL并避免供应商锁定?与MigOps联系,了解我们如何为您提供帮助。