📄 oracle.pm
字号:
my $dbh = shift; my $msg = shift; my $sth = $dbh->prepare_cached(q{ begin dbms_msgpipe.acknowledge(:returnpipe, :errormsg, :param); end; }) or return; $sth->bind_param_inout(":returnpipe", \$msg->[0], 30); $sth->bind_param_inout(":proc", \$msg->[1], 30); $sth->bind_param_inout(":param", \$msg->[2], 4000); $sth->execute or return undef; return 1; } sub ora_server_version { my $dbh = shift; return $dbh->{ora_server_version} if defined $dbh->{ora_server_version}; $dbh->{ora_server_version} = [ split /\./, $dbh->selectrow_array(<<'SQL', undef, 'Oracle%', 'Personal Oracle%') .''];SELECT version FROM product_component_version WHERE product LIKE ? or product LIKE ?SQL } sub ora_nls_parameters { my $dbh = shift; my $refresh = shift; if ($refresh || !$dbh->{ora_nls_parameters}) { my $nls_parameters = $dbh->selectall_arrayref(q{ SELECT parameter, value FROM v$nls_parameters }) or return; $dbh->{ora_nls_parameters} = { map { $_->[0] => $_->[1] } @$nls_parameters }; } # return copy of params to protect against accidental editing my %nls = %{$dbh->{ora_nls_parameters}}; return \%nls; } sub ora_can_unicode { my $dbh = shift; my $refresh = shift; # 0 = No Unicode support. # 1 = National character set is Unicode-based. # 2 = Database character set is Unicode-based. # 3 = Both character sets are Unicode-based. return $dbh->{ora_can_unicode} if defined $dbh->{ora_can_unicode} && !$refresh; my $nls = $dbh->ora_nls_parameters($refresh); $dbh->{ora_can_unicode} = 0; $dbh->{ora_can_unicode} += 1 if $nls->{NLS_NCHAR_CHARACTERSET} =~ /UTF/; $dbh->{ora_can_unicode} += 2 if $nls->{NLS_CHARACTERSET} =~ /UTF/; return $dbh->{ora_can_unicode}; }} # end of package DBD::Oracle::db{ package DBD::Oracle::st; # ====== STATEMENT ====== sub execute_for_fetch { my ($sth, $fetch_tuple_sub, $tuple_status) = @_; my $row_count = 0; my $tuple_count="0E0"; my $tuple_batch_status; my $dbh = $sth->{Database}; my $batch_size =($dbh->{'ora_array_chunk_size'}||= 1000); if(defined($tuple_status)) { @$tuple_status = (); $tuple_batch_status = [ ]; } while (1) { my @tuple_batch; for (my $i = 0; $i < $batch_size; $i++) { push @tuple_batch, [ @{$fetch_tuple_sub->() || last} ]; } last unless @tuple_batch; my $res = ora_execute_array($sth, \@tuple_batch, scalar(@tuple_batch), $tuple_batch_status); if(defined($res) && defined($row_count)) { $row_count += $res; } else { $row_count = undef; } $tuple_count+=@$tuple_batch_status; push @$tuple_status, @$tuple_batch_status if defined($tuple_status); } if (!wantarray) { return undef if !defined $row_count; return $tuple_count; } return (defined $row_count ? $tuple_count : undef, $row_count); } sub private_attribute_info { return { ora_lengths => undef, ora_types => undef, ora_rowid => undef, ora_est_row_width => undef, ora_type => undef, ora_field => undef, ora_csform => undef, ora_maxdata_size => undef, ora_parse_lang => undef, ora_placeholders => undef, ora_auto_lob => undef, ora_check_sql => undef }; } }1;__END__=head1 NAMEDBD::Oracle - Oracle database driver for the DBI module=head1 SYNOPSIS use DBI; $dbh = DBI->connect("dbi:Oracle:$dbname", $user, $passwd); $dbh = DBI->connect("dbi:Oracle:host=$host;sid=$sid", $user, $passwd); # See the DBI module documentation for full details # for some advanced uses you may need Oracle type values: use DBD::Oracle qw(:ora_types);=head1 DESCRIPTIONDBD::Oracle is a Perl module which works with the DBI module to provideaccess to Oracle databases.=head1 CONNECTING TO ORACLEThis is a topic which often causes problems. Mainly due to Oracle's manyand sometimes complex ways of specifying and connecting to databases.(James Taylor and Lane Sharman have contributed much of the text inthis section.)=head2 Connecting without environment variables or tnsnames.ora fileIf you use the C<host=$host;sid=$sid> style syntax, for example: $dbh = DBI->connect("dbi:Oracle:host=myhost.com;sid=ORCL", $user, $passwd);then DBD::Oracle will construct a full connection descriptor stringfor you and Oracle will not need to consult the tnsnames.ora file.If a C<port> number is not specified then the descriptor will try both1526 and 1521 in that order (e.g., new then old). You can check whichport(s) are in use by typing "$ORACLE_HOME/bin/lsnrctl stat" on the server.=head2 Oracle Environment VariablesOracle typically uses two environment variables to specify defaultconnections: ORACLE_SID and TWO_TASK.ORACLE_SID is really unnecessary to set since TWO_TASK provides thesame functionality in addition to allowing remote connections. % setenv TWO_TASK T:hostname:ORACLE_SID # for csh shell $ TWO_TASK=T:hostname:ORACLE_SID export TWO_TASK # for sh shell % sqlplus username/passwordNote that if you have *both* local and remote databases, and youhave ORACLE_SID *and* TWO_TASK set, and you don't specify a fullyqualified connect string on the command line, TWO_TASK takes precedenceover ORACLE_SID (i.e. you get connected to remote system). TWO_TASK=P:sidwill use the pipe driver for local connections using SQL*Net v1. TWO_TASK=T:machine:sidwill use TCP/IP (or D for DECNET, etc.) for remote SQL*Net v1 connection. TWO_TASK=dbnamewill use the info stored in the SQL*Net v2 F<tnsnames.ora>configuration file for local or remote connections.The ORACLE_HOME environment variable should be set correctly.In general, the value used should match the version of Oracle thatwas used to build DBD::Oracle. If using dynamic linking thenORACLE_HOME should match the version of Oracle that will be usedto load in the Oracle client libraries (via LD_LIBRARY_PATH, ldconfig,or similar on Unix).ORACLE_HOME can be left unset if you aren't using any of Oracle'sexecutables, but it is I<not> recommended and error messages may not display.It should be set to the ORACLE_HOME directory of the version of Oraclethat DBD::Oracle was compiled with.Discouraging the use of ORACLE_SID makes it easier on the users to seewhat is going on. (It's unfortunate that TWO_TASK couldn't be renamed,since it makes no sense to the end user, and doesn't have the ORACLE prefix).=head2 Connection Examples Using DBD::OracleFirst, how to connect to a local database I<without> using a Listener: $dbh = DBI->connect('dbi:Oracle:SID','scott', 'tiger');you can also leave the SID empty: $dbh = DBI->connect('dbi:Oracle:','scott', 'tiger');in which case Oracle client code will use the ORACLE_SID environmentvariable (if TWO_TASK env var isn't defined).Below are various ways of connecting to an oracle database usingSQL*Net 1.x and SQL*Net 2.x. "Machine" is the computer the database isrunning on, "SID" is the SID of the database, "DB" is the SQL*Net 2.xconnection descriptor for the database.B<Note:> Some of these formats may not work with Oracle 8+. BEGIN { $ENV{ORACLE_HOME} = '/home/oracle/product/7.x.x'; $ENV{TWO_TASK} = 'DB'; } $dbh = DBI->connect('dbi:Oracle:','scott', 'tiger'); # - or - $dbh = DBI->connect('dbi:Oracle:','scott/tiger');Refer to your Oracle documentation for valid values of TWO_TASK.Here are some variations (not setting TWO_TASK) in order of preference: $dbh = DBI->connect('dbi:Oracle:DB','username','password') $dbh = DBI->connect('dbi:Oracle:DB','username/password','') $dbh = DBI->connect('dbi:Oracle:','username@DB','password') $dbh = DBI->connect('dbi:Oracle:host=foobar;sid=ORCL;port=1521', 'scott/tiger', '') $dbh = DBI->connect('dbi:Oracle:', q{scott/tiger@(DESCRIPTION= (ADDRESS=(PROTOCOL=TCP)(HOST= foobar)(PORT=1521)) (CONNECT_DATA=(SID=ORCL)))}, "")If you are having problems with login taking a long time (>10 secs say)then you might have tripped up on an Oracle bug. You can try using oneof the ...@DB variants as a workaround. E.g., $dbh = DBI->connect('','username/password@DB','');On the other hand, that may cause you to trip up on another Oracle bugthat causes alternating connection attempts to fail! (In reality onlya small proportion of people experience these problems.)To connect to a local database with a user which has been set-up toauthenticate via the OS ("ALTER USER username IDENTIFIED EXTERNALLY"): $dbh = DBI->connect('dbi:Oracle:','/','');Note the lack of a connection name (use the ORACLE_SID environmentvariable). If an explicit SID is used you'll probably get an ORA-01004 error.That only works for local databases. (Authentication to remote Oracledatabases using your unix login name without a password and is possiblebut it's not secure and not recommended so not documented here. If youcan't find the information elsewhere then you probably shouldn't betrying to do it.)=head2 Optimizing Oracle's listener[By Lane Sharman <lane@bienlogic.com>] I spent a LOT of time optimizinglistener.ora and I am including it here for anyone to benefit from. Myconnections over tnslistener on the same humble Netra 1 take an averageof 10-20 milli seconds according to tnsping. If anyone knows how tomake it better, please let me know! LISTENER = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP) (Host = aa.bbb.cc.d) (Port = 1521) (QUEUESIZE=10) ) ) STARTUP_WAIT_TIME_LISTENER = 0 CONNECT_TIMEOUT_LISTENER = 10 TRACE_LEVEL_LISTENER = OFF SID_LIST_LISTENER = (SID_LIST = (SID_DESC = (SID_NAME = xxxx) (ORACLE_HOME = /xxx/local/oracle7-3) (PRESPAWN_MAX = 40) (PRESPAWN_LIST= (PRESPAWN_DESC=(PROTOCOL=tcp) (POOL_SIZE=40) (TIMEOUT=120)) ) ) )1) When the application is co-located on the host AND there is no need foroutside SQLNet connectivity, stop the listener. You do not need it. Getyour application/cgi/whatever working using pipes and shared memory. I amconvinced that this is one of the connection bugs (sockets over the samemachine). Note the $ENV{ORAPIPES} env var. The essential code to dothis at the end of this section.2) Be careful in how you implement the multi-threaded server. Currently Iam not using it in the initxxxx.ora file but will be doing some more testing.3) Be sure to create user rollback segments and use them; do not use thesystem rollback segments; however, you must also create a small rollbackspace for the system as well.5) Use large tuning settings and get lots of RAM. Check out all theparameters you can set in v$parameters because there are quite a few notdocumented you may to set in your initxxx.ora file.6) Use svrmgrl to control oracle from the command line. Write lots of smallSQL scripts to get at V$ info. use DBI; # Environmental variables used by Oracle $ENV{ORACLE_SID} = "xxx"; $ENV{ORACLE_HOME} = "/opt/oracle7"; $ENV{EPC_DISABLED} = "TRUE"; $ENV{ORAPIPES} = "V2"; my $dbname = "xxx"; my $dbuser = "xxx"; my $dbpass = "xxx"; my $dbh = DBI->connect("dbi:Oracle:$dbname", $dbuser, $dbpass) || die "Unable to connect to $dbname: $DBI::errstr\n";=head2 Oracle utilitiesIf you are still having problems connecting then the Oracle adaptersutility may offer some help. Run these two commands: $ORACLE_HOME/bin/adapters $ORACLE_HOME/bin/adapters $ORACLE_HOME/bin/sqlplusand check the output. The "Protocol Adapters" section should be thesame. It should include at least "IPC Protocol Adapter" and "TCP/IPProtocol Adapter".If it generates any errors which look relevant then please talk to yourOracle technical support (and not the dbi-users mailing list). Thanks.Thanks to Mark Dedlow for this information.=head2 Constants=item :ora_session_modes ORA_SYSDBA ORA_SYSOPER=item :ora_types ORA_VARCHAR2 ORA_STRING ORA_NUMBER ORA_LONG ORA_ROWID ORA_DATE ORA_RAW ORA_LONGRAW ORA_CHAR ORA_CHARZ ORA_MLSLABEL ORA_NTY ORA_CLOB ORA_BLOB ORA_RSET ORA_VARCHAR2_TABLE ORA_NUMBER_TABLE SQLT_INT SQLT_FLT =item SQLCS_IMPLICIT=item SQLCS_NCHARSQLCS_IMPLICIT and SQLCS_NCHAR are I<character set form> values.See notes about Unicode elsewhere in this document.=item SQLT_INT=item SQLT_FLTThese types are used only internally, and may be specified as internalbind type for ORA_NUMBER_TABLE. See notes about ORA_NUMBER_TABLE elsewherein this document
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -