专栏首页bisal的个人杂货铺sqlplus执行错误的问题探究

sqlplus执行错误的问题探究

今天碰到个很诡异的问题,在装了Oracle Clinet的机器,不同路径下执行指令sqlplus,回显不同。

Oracle Client路径是/opt/app/oracle/instantclient_11_2,包含如下内容,

bash_profile相关配置,

export ORACLE_HOME=/opt/app/oracle/instantclient_11_2
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ORACLE_HOME
export TNS_ADMIN=$ORACLE_HOME
export CLASSPATH=$ORACLE_HOME/ojdbc6.jar:./
export NLS_LANG="AMERICAN_AMERICA.ZHS16GBK"
export PATH=$PATH:$HOME/.local/bin:$HOME/bin:$SELF_ORACLE_HOME

如果在$ORACLE_HOME,执行sqlplus,提示错误,再次执行,会出core,

[test@localhost instantclient_11_2]$ cd /opt/app/oracle/instantclient_11_2
[test@localhost instantclient_11_2]$ sqlplus
Error 6 initializing SQL*Plus
SP2-0667: Message file sp1<lang>.msb not found
SP2-0750: You may need to set ORACLE_HOME to your Oracle software directory

如果在其他路径(非$ORACLE_HOME),执行sqlplus,回显正常,

[test@localhost instantclient_11_2]$ sqlplus
SQL*Plus: Release 11.2.0.4.0 Production on Wed Jul 22 17:48:07 2020
Copyright (c) 1982, 2013, Oracle. All rights reserved.
Enter user-name:

这是为什么?

通过strace发现了其中一些区别,sqlplus执行异常的strace片段,

[test@localhost instantclient_11_2]$ strace sqlplus
execve("/opt/app/oracle/instantclient_11_2/sqlplus", ["sqlplus"], [/* 29 vars */]) = 0
brk(NULL) = 0x1b20000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9cb847c000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("tls/x86_64/libsqlplus.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("tls/libsqlplus.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("x86_64/libsqlplus.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("libsqlplus.so", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0@\370\1\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0555, st_size=1469542, ...}) = 0
getcwd("/opt/app/oracle/instantclient_11_2", 128) = 54

sqlplus执行正常的strace片段,

[test@localhost instantclient_11_2]$ strace sqlplus
execve("/opt/app/oracle/instantclient_11_2/sqlplus", ["sqlplus"], [/* 28 vars */]) = 0
brk(NULL) = 0x16ec000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fcd72b26000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("tls/x86_64/libsqlplus.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("tls/libsqlplus.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("x86_64/libsqlplus.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("libsqlplus.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/opt/app/oracle/instantclient_11_2/tls/x86_64/libsqlplus.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/opt/app/oracle/instantclient_11_2/tls/x86_64", 0x7fff93de3060) = -1 ENOENT (No such file or directory)
open("/opt/app/oracle/instantclient_11_2/tls/libsqlplus.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/opt/app/oracle/instantclient_11_2/tls", 0x7fff93de3060) = -1 ENOENT (No such file or directory)
open("/opt/app/oracle/instantclient_11_2/x86_64/libsqlplus.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/opt/app/oracle/instantclient_11_2/x86_64", 0x7fff93de3060) = -1 ENOENT (No such file or directory)
open("/opt/app/oracle/instantclient_11_2/libsqlplus.so", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0@\370\1\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0555, st_size=1469542, ...}) = 0
mmap(NULL, 1985056, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fcd72941000
mprotect(0x7fcd72a17000, 1048576, PROT_NONE) = 0
mmap(0x7fcd72b17000, 57344, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xd6000) = 0x7fcd72b17000
mmap(0x7fcd72b25000, 2592, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fcd72b25000
close(3) = 0

对比一下,可以看到,sqlplus执行异常的strace,打开libsqlplus.so成功,

open("libsqlplus.so", O_RDONLY|O_CLOEXEC) = 3

sqlplus执行正常的strace,打开libsqlplus.so失败,然后打开了带路径的,

open("libsqlplus.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
...
open("/opt/app/oracle/instantclient_11_2/libsqlplus.so", O_RDONLY|O_CLOEXEC) = 3

如果说是解决,在LD_LIBRARY_PATH中开始处增加".",就是当前路径,此时无论在不在$ORACLE_HOME,sqlplus都可以正常执行,

export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH:$ORACLE_HOME

但是,原因是什么?

众所周知,LD_LIBRARY_PATH是Linux环境变量名,该环境变量主要用于指定查找共享库(动态链接库,例如此处的libsqlplus.so)时除了默认路径之外的其他路径。

当执行函数动态链接.so时,如果此文件不在缺省目录下/lib和/usr/lib,那么就需要指定环境变量LD_LIBRARY_PATH,有时候我们安装的软件,因为没root权限,不会放到这些系统路径下,因此要改LD_LIBRARY_PATH,指定查找的路径。因此,运行时动态库的搜索路径就需要先后顺序, 1. 编译目标代码时指定的动态库搜索路径。 2. 环境变量LD_LIBRARY_PATH指定的动态库搜索路径。 3 .配置文件/etc/ld.so.conf中指定的动态库搜索路径。 4. 默认的动态库搜索路径/lib和/usr/lib。

再回到这个问题,同样在$ORACLE_HOME路径下,执行sqlplus,strace的回显还是一样,但此时执行成功,说明sqlplus的执行路径是没问题的,关键还是LD_LIBRARY_PATH将"."当前路径加入了其中,

[test@localhost instantclient_11_2]$ strace sqlplus
execve("./sqlplus", ["sqlplus"], [/* 28 vars */]) = 0
brk(0) = 0x22c0000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f30b4903000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("./tls/x86_64/libsqlplus.so", O_RDONLY) = -1 ENOENT (No such file or directory)
open("./tls/libsqlplus.so", O_RDONLY) = -1 ENOENT (No such file or directory)
open("./x86_64/libsqlplus.so", O_RDONLY) = -1 ENOENT (No such file or directory)
open("./libsqlplus.so", O_RDONLY) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0@\370\1\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0555, st_size=1469542, ...}) = 0
getcwd("/opt/app/oracle/instantclient_11_2", 128) = 58

对这个问题原因,还是有些含糊,这种解释,有些牵强,

1.不在$ORACLE_HOME执行,当前路径没libsqlplus.so,因此会到LD_LIBRARY_PATH定义的$ORACLE_HOME中找到带全路径的libsqlplus.so。

2.在$ORACLE_HOME执行,当前路径存在libsqlplus.so,但是LD_LIBRARY_PATH没定义"."当前路径,加载失败,当加入"."定义后,执行成功。

这个应该不是一个难题,还是考察的对环境变量的理解和运用,因此,还是希望各位路过的朋友、大神,能指点一二,找到合理的解释,在此谢过。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 使用dbms_stat采集统计信息时estimate_percent和cascade的默认值

    收集统计信息可以用dbms_stats包,通常用这样的语法:exec dbms_stat.gather_table_stats(ownname=>'xxx', ...

    bisal
  • 实验理解ADMIN OPTION和GRANT OPTION的用法

    使用GRANT赋予用户权限的时候通常有ADMIN OPTION和GRANT OPTION这两个OPTION。下面使用简单的实验来体会下这两种授权的用途。

    bisal
  • Linux下的^M困惑

    我们有时在Windows编辑的文件,放到了Linux环境中,打开文件,可能发现每行结尾多了一个“^M”,导致一些在Windows下能执行的解析程序,放到了Lin...

    bisal
  • 币聪科技:TenX推出新的品牌和借记卡设计

    TenX的使命是“为全世界尽可能多的人提供加密货币。”这个新加坡的区块链项目一直在努力使加密货币随时随地都可以随时消费。

    币聪财经
  • 【POJ 1389】Area of Simple Polygons(线段树+扫描线,矩形并面积)

    要么在相差大于1的两点间加入一个值,要么就让左右端点为l,r的线段树节点表示到x[l]到x[r+1]的区间。

    饶文津
  • 【Yellow Cards CodeForces - 1215A 】【贪心】

    该题难点在于求最小的离开数,最大的没什么好说的,关键是求最小的。 可以这样去想,最小的离开数就是每个人获得的牌数等于他所能接受的最大牌数-1,这样就可以直接比...

    _DIY
  • 使用Java+SAP云平台+SAP Cloud Connector调用ABAP On-Premise系统里的函数

    最近Jerry接到一个原型开发的任务,需要在微信里调用ABAP On Premise系统(SAP CRM On-Premise)里的某些函数。具体场景和我之前的...

    Jerry Wang
  • bzoj3884: 上帝与集合的正确用法 欧拉降幂

    用户2965768
  • eclipse的thrift插件

    插件网址为:http://thrift4eclipse.sourceforge.net/en/install.html,经测试对Eclipse 4.4.2也有...

    一见
  • Linux中if-else条件判断语句

    其中elif和else不是必须的,如果只需判断一次,那么if...fi即可。值得注意的是if后面中括号[]中的语句[的后面和]的前面必须要有空格。

    生信编程日常

扫码关注云+社区

领取腾讯云代金券