11# ------------------------------------------------------------------------------
2- # Copyright (c) 2022, Oracle and/or its affiliates.
2+ # Copyright (c) 2022, 2023, Oracle and/or its affiliates.
33#
44# This software is dual-licensed to you under the Universal Permissive License
55# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
@@ -169,8 +169,6 @@ cdef class ConnectParamsImpl:
169169 self ._default_address.set_from_args(args)
170170 _set_bool_param(args, " externalauth" , & self .externalauth)
171171 self ._set_access_token_param(args.get(" access_token" ))
172- if args:
173- self ._has_components = True
174172
175173 cdef int _check_credentials(self ) except - 1 :
176174 """
@@ -344,7 +342,6 @@ cdef class ConnectParamsImpl:
344342 # to be a full connect descriptor
345343 if connect_string.startswith(" (" ):
346344 _parse_connect_descriptor(connect_string, args)
347- self ._has_components = True
348345 return self ._process_connect_descriptor(args)
349346
350347 # otherwise, see if the connect string is an EasyConnect string
@@ -389,9 +386,6 @@ cdef class ConnectParamsImpl:
389386 _parse_connect_descriptor(connect_string, args)
390387 self ._process_connect_descriptor(args)
391388
392- # mark that object has components
393- self ._has_components = True
394-
395389 cdef int _process_connect_descriptor(self , dict args) except - 1 :
396390 """
397391 Internal method used for processing the parsed connect descriptor into
@@ -538,8 +532,7 @@ cdef class ConnectParamsImpl:
538532 will be a connect string built up from the components supplied when the
539533 object was built.
540534 """
541- if self ._has_components:
542- return self .description_list.build_connect_string()
535+ return self .description_list.build_connect_string()
543536
544537 def get_full_user (self ):
545538 """
@@ -613,16 +606,18 @@ cdef class Address:
613606
614607 cdef str build_connect_string(self ):
615608 """
616- Build a connect string from the components.
609+ Build a connect string from the components. If no host is specified,
610+ None is returned (used for bequeath connections).
617611 """
618- parts = [f" (PROTOCOL={self.protocol})" ,
619- f" (HOST={self.host})" ,
620- f" (PORT={self.port})" ]
621- if self .https_proxy is not None :
622- parts.append(f" (HTTPS_PROXY={self.https_proxy})" )
623- if self .https_proxy_port != 0 :
624- parts.append(f" (HTTPS_PROXY_PORT={self.https_proxy_port})" )
625- return f' (ADDRESS={"".join(parts)})'
612+ if self .host is not None :
613+ parts = [f" (PROTOCOL={self.protocol})" ,
614+ f" (HOST={self.host})" ,
615+ f" (PORT={self.port})" ]
616+ if self .https_proxy is not None :
617+ parts.append(f" (HTTPS_PROXY={self.https_proxy})" )
618+ if self .https_proxy_port != 0 :
619+ parts.append(f" (HTTPS_PROXY_PORT={self.https_proxy_port})" )
620+ return f' (ADDRESS={"".join(parts)})'
626621
627622 def copy (self ):
628623 """
@@ -667,12 +662,25 @@ cdef class AddressList:
667662 def __init__ (self ):
668663 self .addresses = []
669664
665+ cdef bint _uses_tcps(self ):
666+ """
667+ Returns a boolean indicating if any of the addresses in the address
668+ list use the protocol TCPS.
669+ """
670+ cdef Address address
671+ for address in self .addresses:
672+ if address.protocol == " tcps" :
673+ return True
674+ return False
675+
670676 cdef str build_connect_string(self ):
671677 """
672678 Build a connect string from the components.
673679 """
674680 cdef Address a
675681 parts = [a.build_connect_string() for a in self .addresses]
682+ if len (parts) == 1 :
683+ return parts[0 ]
676684 return f' (ADDRESS_LIST={"".join(parts)})'
677685
678686 def set_from_args (self , dict args ):
@@ -713,37 +721,12 @@ cdef class Description:
713721 Build a connect string from the components.
714722 """
715723 cdef:
716- str connect_data, security, temp
717- list parts, address_lists
718- AddressList a
719-
720- # build connect data segment
721- parts = []
722- if self .service_name is not None :
723- parts.append(f" (SERVICE_NAME={self.service_name})" )
724- elif self .sid is not None :
725- parts.append(f" (SID={self.sid})" )
726- if self .server_type is not None :
727- parts.append(f" (SERVER={self.server_type})" )
728- if self .cclass is not None :
729- parts.append(f" (POOL_CONNECTION_CLASS={self.cclass})" )
730- if self .purity != 0 :
731- parts.append(f" (POOL_PURITY={self.purity})" )
732- if cid is not None :
733- parts.append(f" (CID={cid})" )
734- connect_data = f' (CONNECT_DATA={"".join(parts)})'
724+ AddressList address_list
725+ list parts, temp_parts
726+ bint uses_tcps = False
727+ str temp
735728
736- # build security segment, if applicable
737- parts = []
738- if self .ssl_server_dn_match:
739- parts.append(" (SSL_SERVER_DN_MATCH=ON)" )
740- if self .ssl_server_cert_dn is not None :
741- parts.append(f" (SSL_SERVER_CERT_DN={self.ssl_server_cert_dn})" )
742- if self .wallet_location is not None :
743- parts.append(f" (MY_WALLET_DIRECTORY={self.wallet_location})" )
744- security = f' (SECURITY={"".join(parts)})'
745-
746- # build connect string
729+ # build top-level description parts
747730 parts = []
748731 if self .load_balance:
749732 parts.append(" (LOAD_BALANCE=ON)" )
@@ -758,10 +741,48 @@ cdef class Description:
758741 if self .tcp_connect_timeout != DEFAULT_TCP_CONNECT_TIMEOUT:
759742 temp = self ._build_duration_str(self .tcp_connect_timeout)
760743 parts.append(f" (TRANSPORT_CONNECT_TIMEOUT={temp})" )
761- address_lists = [a.build_connect_string() for a in self .address_lists]
762- parts.extend(address_lists)
763- parts.append(connect_data)
764- parts.append(security)
744+
745+ # add address lists, but if the address list contains only a single
746+ # entry and that entry does not have a host, the other parts aren't
747+ # relevant anyway!
748+ for address_list in self .address_lists:
749+ temp = address_list.build_connect_string()
750+ if temp is None :
751+ return None
752+ parts.append(temp)
753+ if not uses_tcps:
754+ uses_tcps = address_list._uses_tcps()
755+
756+ # build connect data segment
757+ temp_parts = []
758+ if self .service_name is not None :
759+ temp_parts.append(f" (SERVICE_NAME={self.service_name})" )
760+ elif self .sid is not None :
761+ temp_parts.append(f" (SID={self.sid})" )
762+ if self .server_type is not None :
763+ temp_parts.append(f" (SERVER={self.server_type})" )
764+ if self .cclass is not None :
765+ temp_parts.append(f" (POOL_CONNECTION_CLASS={self.cclass})" )
766+ if self .purity != 0 :
767+ temp_parts.append(f" (POOL_PURITY={self.purity})" )
768+ if cid is not None :
769+ temp_parts.append(f" (CID={cid})" )
770+ if temp_parts:
771+ parts.append(f' (CONNECT_DATA={"".join(temp_parts)})' )
772+
773+ # build security segment, if applicable
774+ if uses_tcps:
775+ temp_parts = []
776+ if self .ssl_server_dn_match:
777+ temp_parts.append(" (SSL_SERVER_DN_MATCH=ON)" )
778+ if self .ssl_server_cert_dn is not None :
779+ temp = f" (SSL_SERVER_CERT_DN={self.ssl_server_cert_dn})"
780+ temp_parts.append(temp)
781+ if self .wallet_location is not None :
782+ temp = f" (MY_WALLET_DIRECTORY={self.wallet_location})"
783+ temp_parts.append(temp)
784+ parts.append(f' (SECURITY={"".join(temp_parts)})' )
785+
765786 return f' (DESCRIPTION={"".join(parts)})'
766787
767788 def copy (self ):
0 commit comments