python-oracledb icon indicating copy to clipboard operation
python-oracledb copied to clipboard

DPY-4000 when using EZCONNECT syntax (which worked with 1.2.1)

Open hvbtup opened this issue 1 year ago • 5 comments

  1. What versions are you using?

DB: Oracle Database 12c Standard Edition Release 12.2.0.1.0 - 64bit Production

Also run Python and show the output of ...:

platform.platform: Windows-2012ServerR2-6.3.9600-SP0 sys.maxsize > 2**32: True platform.python_version: 3.10.7

oracledb.version: 2.2.1

  1. Is it an error or a hang or a crash?

Crash

While this worked with oracledb-1.2.1. I only switched to 2.2.1 because I saw the exception from https://github.com/oracle/python-oracledb/issues/30 in a call to executemany with 1.2.1.

  1. What error(s) or behavior you are seeing?

... File "E:...\ROG\import_service\python\import_service.py", line 144, in connect self._conn = oracledb.connect(self.connect_string) File "E:...import_service\3rdParty\python-3.10\lib\site-packages\oracledb\connection.py", line 1158, in connect return conn_class(dsn=dsn, pool=pool, params=params, **kwargs) File "E:...\import_service\3rdParty\python-3.10\lib\site-packages\oracledb\connection.py", line 517, in init dsn = params_impl.process_args(dsn, kwargs, thin) File "src\oracledb\impl/base/connect_params.pyx", line 623, in oracledb.base_impl.ConnectParamsImpl.process_args File "src\oracledb\impl/base/connect_params.pyx", line 560, in oracledb.base_impl.ConnectParamsImpl.parse_connect_string File "src\oracledb\impl/base/connect_params.pyx", line 558, in oracledb.base_impl.ConnectParamsImpl.parse_connect_string File "src\oracledb\impl/base/connect_params.pyx", line 338, in oracledb.base_impl.ConnectParamsImpl._parse_connect_string File "E:...\import_service\3rdParty\python-3.10\lib\site-packages\oracledb\errors.py", line 182, in _raise_err raise error.exc_type(error) from cause oracledb.exceptions.DatabaseError: DPY-4000: unable to find "//rocket:1521/E122" in E:...\import_service\conf\tnsnames.ora

The application uses a string of the following form as self.connect_string:

username/password@//rocket:1521/E122

Username and password contain only ASCII letters.

  1. Does your application call init_oracle_client()?

No (Thin mode).

This is probably important:

The program just calls oracledb.connect(x) with a single string x of the form mentioned above.

The environment variable TNS_ADMIN is set and points to a directory with sqlnet.ora and tnsnames.ora. I know that these files are not necessary when using EZCONNECT syntax, but the program is written generic (also supports Thick Mode and TNS aliases).

Contents of tnsnames.ora:

TEST.world =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = oracle-db.local)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = TEST)
    )
  )

Contents of sqlnet.ora:

NAMES.DIRECTORY_PATH= (TNSNAMES,EZCONNECT)
  1. Include a runnable Python script that shows the problem.

Format code by using three backticks on a line before and after code snippets, for example:

import oracledb
import os
os.environ["TNS_ADMIN"] = r"E:\...\import_service\conf"
oracledb.connect("username/password@//rocket:1521/E122")

hvbtup avatar Jun 28 '24 09:06 hvbtup

Of course you have to adapt the TNS_ADMIN path accordingly in order to test.

hvbtup avatar Jun 28 '24 10:06 hvbtup

This is a 'known feature' - I don't even remember it working at all, but guess it must have. Just this week we were talking about it, and the need for a better parser.

The solution is to remove the nominally-optional "//". Try oracledb.connect("username/password@rocket:1521/E122")

cjbj avatar Jun 29 '24 07:06 cjbj

It wouldn't have worked in thin mode at any time, but it would have (and still does) work in thick mode. The main reason it wouldn't have worked in thin mode is because I didn't even know about it until very recently. :-) As Chris mentioned, remove the "//" which shouldn't be there. Or add the protocol ("tcp:") before the "//". As Chris mentioned a better parser is being considered, but this is the least of the issues that needs to be resolved!

anthony-tuininga avatar Jun 29 '24 14:06 anthony-tuininga

Well, considering I used to favor & document the use of the optional '//', and it's part of the official syntax, I wouldn't go so far as to say it shouldn't be there!

cjbj avatar Jun 30 '24 03:06 cjbj

@anthony-tuininga I can confirm that the EZCONNECT syntax definitely worked in thin mode in 1.2.1.

hvbtup avatar Jul 01 '24 10:07 hvbtup

I presume that removeing the // resolves the issue for you? It is possible that it stopped working when the improved regex was introduced (to resolve a different issue). You're the first to note the failure with the // (degenerate form of the protocol designation). In any case, I will look at adding the improved parser that was discussed.

anthony-tuininga avatar Aug 02 '24 21:08 anthony-tuininga

Last week, I finally found an official syntax description (for the new "Easy Connect Plus" syntax, however) at https://download.oracle.com/ocomdocs/global/Oracle-Net-Easy-Connect-Plus.pdf

According to this document, //server:port/service_name is invalid. It should be either tcp://.... or without //.

BTW: Anthony, since you are working for Oracle now: My co-workers tell me that they really would appreciate if all those Oracle client drivers would behave the same regarding SQL*Net (for example, use the same environment variables like TNS_ADMIN, consider tnsnames.ora AND sqlnet.ora, etc).

I will test later today if removing // resolves the issue...

hvbtup avatar Aug 07 '24 07:08 hvbtup

That tech brief (which I originally released for the Net team, but is now coordinated by @sharadraju) shows the syntax as [[protocol:]//]... which means it doesn't need a protocol, and can optionally start with "//".

The actual official syntax varies with which version of the Thick client is in use - and which of those variants is implemented in the relevant Thin client! For example the 23ai Thick client syntax is documented in the Database Net Services Administrator's Guide. (BTW, this is linked to from the python-oracledb doc on the Easy Connect syntax).

Regarding the use of '//', @anthony-tuininga is finalizing a new connection string parser, so I will hold him to supporting an optional '//'.

Regarding your final request, the overall direction is for standardization across drivers. Now that JDBC is under the same management line, there is considerable coordination across all Oracle drivers. Unfortunately we can't dramatically rationalize and simplify configuration files syntaxes or search paths, due to their long history and widespread use.

cjbj avatar Aug 07 '24 11:08 cjbj

I presume that removeing the // resolves the issue for you?

Yes, using just username/password@server:port/service_name resolves the issue.

hvbtup avatar Aug 07 '24 11:08 hvbtup

I have pushed a patch that corrects this issue. If you are able to build from source you can verify that it works for you, too.

anthony-tuininga avatar Aug 13 '24 17:08 anthony-tuininga

Sorry, I can't build from source. Guess I'll just have to wait for the next release.

hvbtup avatar Aug 14 '24 07:08 hvbtup

This was included in python-oracledb 2.4.0 which was just released.

anthony-tuininga avatar Aug 20 '24 21:08 anthony-tuininga