oracle资料库函式库

  •   2009-07-31/22:56
  • <?
    class DB_Sql {
    var $Debug = false;
    var $Home = "/u01/app/oracle/product/8.0.4";
    var $Remote = 1;
    /* This Query will be sent directly after the first connection
    Example:
    var $ConnectQuery="ALTER SESSION SET nls_date_language=german nls_date_format='DD.MM.RRRR'";
    -> Set the date format for this session, this is fine when your ora-role
    cannot be altered */
    var $ConnectQuery='';
    /* Due to a strange error with Oracle 8.0.5, Apache and PHP3.0.6
    you don't need to set the ENV - on my system Apache
    will change to a zombie, if I don't set this to FALSE!
    Instead I set these ENV-vars before the startup of apache.
    If unsure try it out, if it works. */
    var $OraPutEnv = true;

    var $Database = "";
    var $User = "";
    var $Password = "";

    var $Link_ID = 0;
    var $Query_ID = 0;
    var $Record = array();
    var $Row;

    var $Errno = 0;
    var $Error = "";
    var $ora_no_next_fetch=false;


    /* copied from db_mysql for completeness */
    /* public: identification constant. never change this. */
    var $type = "oracle";
    var $revision = "Revision: 1.3";
    var $Halt_On_Error = "yes"; ## "yes" (halt with message), "no" (ignore errors quietly), "report" (ignore errror, but spit a warning)

    /* public: constructor */
    function DB_Sql($query = "") {
    $this->query($query);
    }

    /* public: some trivial reporting */
    function link_id() {
    return $this->Link_ID;
    }

    function query_id() {
    return $this->Query_ID;
    }

    function connect() {
    ## see above why we do this
    if ($this->OraPutEnv) {
    PutEnv("ORACLE_SID=$this->Database");
    PutEnv("ORACLE_HOME=$this->Home");
    }
    if ( 0 == $this->Link_ID ) {
    if($this->Debug) {
    printf("<br>Connect()ing to $this->Database...<br>n");
    }
    if($this->Remote) {
    if($this->Debug) {
    printf("<br>connect() $this->User/******@$this->Database<br>n");
    }  
    $this->Link_ID=ora_plogon
    ("$this->User/$this->Password@$this->Database","");
    /************** (comment by SSilk)
    this dosn't work on my system:
    $this->Link_ID=ora_plogon
    ("$this->User@$this->Database.world","$this->Password");
    ***************/
    } else {
    if($this->Debug) {
    printf("<br>connect() $this->User, $this->Password <br>n");
    }  
    $this->Link_ID=ora_plogon("$this->User","$this->Password");
    /* (comment by SSilk: don't know how this could work, but I leave this untouched!) */
    }
    if($this->Debug) {
    printf("<br>connect() Link_ID: $this->Link_ID<br>n");
    }
    if (!$this->Link_ID) {
    $this->halt("connect() Link-ID == false " .
    "($this->Link_ID), ora_plogon failed");
    } else {
    //echo "commit on<p>";
    ora_commiton($this->Link_ID);
    }
    if($this->Debug) {
    printf("<br>connect() Obtained the Link_ID: $this->Link_ID<br>n");
    }
    ## Execute Connect Query
    if ($this->ConnectQuery) {
    $this->query($this->ConnectQuery);
    }
    }
    }

    ## In order to increase the # of cursors per system/user go edit the
    ## init.ora file and increase the max_open_cursors parameter. Yours is on
    ## the default value, 100 per user.
    ## We tried to change the behaviour of query() in a way, that it tries
    ## to safe cursors, but on the other side be carefull with this, that you
    ## don't use an old result.
    ##  
    ## You can also make extensive use of ->disconnect()!
    ## The unused QueryIDs will be recycled sometimes.  

    function query($Query_String)  
    {

    /* No empty query please. */
    if (empty($Query_String))
    {
    return 0;
    }

    $this->connect();
    $this->lastQuery=$Query_String;

    if (!$this->Query_ID) {
    $this->Query_ID= ora_open($this->Link_ID);
    }
    if($this->Debug) {
    printf("Debug: query = %s<br>n", $Query_String);
    printf("<br>Debug: Query_ID: %d<br>n", $this->Query_ID);
    }

    if(!@ora_parse($this->Query_ID,$Query_String)) {
    $this->Errno=ora_errorcode($this->Query_ID);
    $this->Error=ora_error($this->Query_ID);
    $this->halt("<BR>ora_parse() failed:<BR>$Query_String<BR><small>Snap & paste this to sqlplus!</SMALL>");
    } elseif (!@ora_exec($this->Query_ID)) {
    $this->Errno=ora_errorcode($this->Query_ID);
    $this->Error=ora_error($this->Query_ID);
    $this->halt("<BR>n$Query_Stringn<BR><small>Snap & paste this to sqlplus!</SMALL>");
    }

    $this->Row=0;

    if(!$this->Query_ID) {
    $this->halt("Invalid SQL: ".$Query_String);
    }

    return $this->Query_ID;
    }

    function next_record() {
    if (!$this->ora_no_next_fetch &&  
    0 == ora_fetch($this->Query_ID)) {
    if ($this->Debug) {
    printf("<br>next_record(): ID: %d Row: %d<br>n",
    $this->Query_ID,$this->Row+1);
    // more info for $this->Row+1 is $this->num_rows(),
    // but dosn't work in all cases (complicated selects)
    // and it is very slow here
    }
    $this->Row +=1;

    $errno=ora_errorcode($this->Query_ID);
    if(1403 == $errno) { # 1043 means no more records found
    $this->Errno=0;
    $this->Error="";
    $this->disconnect();
    $stat=0;
    } else {
    $this->Error=ora_error($this->Query_ID);
    $this->Errno=$errno;
    if($this->Debug) {
    printf("<br>%d Error: %s",
    $this->Errno,
    $this->Error);
    }
    $stat=0;
    }
    } else {
    $this->ora_no_next_fetch=false;
    for($ix=0;$ix<ora_numcols($this->Query_ID);$ix++) {
    $col=strtolower(ora_columnname($this->Query_ID,$ix));
    $value=ora_getcolumn($this->Query_ID,$ix);
    $this->Record[ "$col" ] = $value;
    $this->Record[ $ix ] = $value;
    #DBG echo"<b>[$col]</b>: $value <br>n";
    }
    $stat=1;
    }

    return $stat;
    }

    ## seek() works only for $pos - 1 and $pos
    ## Perhaps I make a own implementation, but my
    ## opinion is, that this should be done by PHP3
    function seek($pos) {
    if ($this->Row - 1 == $pos) {
    $this->ora_no_next_fetch=true;
    } elseif ($this->Row == $pos ) {
    ## do nothing
    } else {
    $this->halt("Invalid seek(): Position is cannot be handled by API.<BR>".
    "Only a seek to the last element is allowed in this version<BR>".
    "Difference too big. Wanted: $pos Current pos: $this->Row");
    }
    if ($this->Debug) echo "<BR>Debug: seek = $pos<BR>";
    $this->Row=$pos;
    }

    function lock($table, $mode = "write") {
    if ($mode == "write") {
    $result = ora_do($this->Link_ID, "lock table $table in row exclusive mode");
    } else {
    $result = 1;
    }
    return $result;
    }

    function unlock() {
    return ora_do($this->Link_ID, "commit");
    }

    // Important note: This function dosn't work with Oracle-Database-Links!
    // You are free to get a better method. :)
    function metadata($table,$full=false) {
    $count = 0;
    $id = 0;
    $res = array();

    /*
    * Due to compatibility problems with Table we changed the behavior
    * of metadata();
    * depending on $full, metadata returns the following values:
    *
    * - full is false (default):
    * $result[]:
    * [0]["table"] table name
    * [0]["name"] field name
    * [0]["type"] field type
    * [0]["len"] field length
    * [0]["flags"] field flags ("NOT NULL", "INDEX")
    * [0]["format"] precision and scale of number (eg. "10,2") or empty
    * [0]["index"] name of index (if has one)
    * [0]["chars"] number of chars (if any char-type)
    *
    * - full is true
    * $result[]:
    * ["num_fields"] number of metadata records
    * [0]["table"] table name
    * [0]["name"] field name
    * [0]["type"] field type
    * [0]["len"] field length
    * [0]["flags"] field flags ("NOT NULL", "INDEX")
    * [0]["format"] precision and scale of number (eg. "10,2") or empty
    * [0]["index"] name of index (if has one)
    * [0]["chars"] number of chars (if any char-type)
    * [0]["php_type"] the correspondig PHP-type
    * [0]["php_subtype"] the subtype of PHP-type
    * ["meta"][field name] index of field named "field name"
    * This could used, if you have the name, but no index-num - very fast
    * Test: if (isset($result['meta']['myfield'])) {} ...
    */

    $this->connect();

    ## This is a RIGHT OUTER JOIN: "(+)", if you want to see, what
    ## this query results try the following:
    ## $table = new Table; $db = new my_DB_Sql; # you have to make
    ## # your own class
    ## $table->show_results($db->query(see query vvvvvv))
    ##
    $this->query("SELECT T.table_name,T.column_name,T.data_type,".
    "T.data_length,T.data_precision,T.data_scale,T.nullable,".
    "T.char_col_decl_length,I.index_name".
    " FROM ALL_TAB_COLUMNS T,ALL_IND_COLUMNS I".
    " WHERE T.column_name=I.column_name (+)".
    " AND T.table_name=I.table_name (+)".
    " AND T.table_name=UPPER('$table') ORDER BY T.column_id");

    $i=0;
    while ($this->next_record()) {
    $res[$i]["table"] = $this->Record[table_name];
    $res[$i]["name"] = strtolower($this->Record[column_name]);
    $res[$i]["type"] = $this->Record[data_type];
    $res[$i]["len"] = $this->Record[data_length];
    if ($this->Record[index_name]) $res[$i]["flags"] = "INDEX ";
    $res[$i]["flags"] .= ( $this->Record[nullable] == 'N') ? '' : 'NOT NULL';
    $res[$i]["format"]= (int)$this->Record[data_precision].",".
    (int)$this->Record[data_scale];
    if ("0,0"==$res[$i]["format"]) $res[$i]["format"]='';
    $res[$i]["index"] = $this->Record[index_name];
    $res[$i]["chars"] = $this->Record[char_col_decl_length];
    if ($full) {
    $j=$res[$i]["name"];
    $res["meta"][$j] = $i;
    $res["meta"][strtoupper($j)] = $i;
    switch ($res[$i]["type"]) {
    case "VARCHAR2" :
    case "VARCHAR" :
    case "CHAR" :
    $res["php_type"]="string";
    $res["php_subtype"]="";
    break;
    case "DATE" :
    $res["php_type"]="string";
    $res["php_subtype"]="date";
    break;
    case "BLOB" :
    case "CLOB" :
    case "BFILE" :
    case "RAW" :
    case "LONG" :
    case "LONG RAW" :
    $res["php_type"]="string";
    $res["php_subtype"]="blob";
    break;
    case "NUMBER" :
    if ($res[$i]["format"]) {
    $res["php_type"]="double";
    $res["php_subtype"]="";
    } else {
    $res["php_type"]="int";
    $res["php_subtype"]="";
    }
    break;
    default :
    $this->halt("metadata(): Type is not a valid value: '$res[$i][type]'");
    break;
    }
    }
    if ($full) $res["meta"][$res[$i]["name"]] = $i;
    $i++;
    }
    if ($full) $res["num_fields"]=$i;
    # $this->disconnect();
    return $res;
    }

    ## THIS FUNCTION IS UNSTESTED!
    function affected_rows() {
    if ($this->Debug) echo "<BR>Debug: affected_rows=". ora_numrows($this->Query_ID)."<BR>";
    return ora_numrows($this->Query_ID);
    }

    ## Known bugs: It will not work for SELECT DISTINCT and any
    ## other constructs which are depending on the resulting rows.
    ## So you *really need* to check every query you make, if it
    ## will work with it!
    ##
    ## Also, for a qualified replacement you need to parse the
    ## selection, cause this will fail: "SELECT id, from FROM ...").
    ## "from" is - as far as I know a keyword in Oracle, so it can
    ## only be used in this way. But you have been warned.
    function num_rows() {
    $curs=ora_open($this->Link_ID);

    ## this is the important part and it is also the HACK!
    if (eregi("^[[:space:]]*SELECT[[:space:]]",$this->lastQuery) )  
    {

    # This works for all?? cases, including SELECT DISTINCT case.
    # We just make select count(*) from original sql expression
    # and remove ORDER BY (if any) for speed
    # I like regular expressions too ;-)))  
    $q = sprintf("SELECT COUNT(*) FROM (%s)",
    @eregi_Replace("ORDER[[:space:]]+BY[^)]*()*)", "\1",  
    $this->lastQuery)  
    );

    # works also for subselects:
    # if (eregi("[[:space:]]+FROM([[:space:]]+.*[[:space:]]+FROM)",$this->lastQuery,$r))
    # $areplace=$r[1];
    # $q=eregi_Replace("^[[:space:]]*SELECT[[:space:]]+".
    # ".*[[:space:]]+FROM",
    # "SELECT COUNT(*) FROM$areplace",
    # $this->lastQuery);

    if ($this->Debug) echo "<BR>Debug: num_rows: $q<BR>";

    ORA_parse($curs,$q);
    ORA_exec($curs);
    ORA_fetch($curs);
    $result = ORA_getcolumn($curs,0);
    ORA_close($curs);
    if ($this->Debug)
    {  
    echo "<BR>Debug: ID ".$this->QueryID.
    " num_rows=". $result ."<BR>";
    }
    return $result;
    }  
    else  
    {
    $this->halt("Last Query was not a SELECT: $this->lastQuery");
    }
    }

    function num_fields() {
    if ($this->Debug) echo "<BR>Debug: num_fields=". ora_numcols($this->Query_ID) . "<BR>";
    return ora_numcols($this->Query_ID);
    }

    function nf() {
    return $this->num_rows();
    }

    function np() {
    print $this->num_rows();
    }

    function f($Name) {
    return $this->Record[$Name];
    }

    function p($Name) {
    print $this->Record[$Name];
    }

    /* public: sequence number */
    function nextid($seq_name)
    {
    $this->connect();

    /* Independent Query_ID */
    $Query_ID = ora_open($this->Link_ID);

    if(!@ora_parse($Query_ID,"SELECT $seq_name.NEXTVAL FROM DUAL"))  
    {
    // There is no such sequence yet, then create it
    if(!@ora_parse($Query_ID,"CREATE SEQUENCE $seq_name")  
    ||
    !@ora_exec($Query_ID)
    )
    {
    $this->halt("<BR> nextid() function - unable to create sequence");
    return 0;
    }
    @ora_parse($Query_ID,"SELECT $seq_name.NEXTVAL FROM DUAL");
    }  
    if (!@ora_exec($Query_ID)) {
    $this->halt("<BR>ora_exec() failed:<BR>nextID function");
    }
    if (@ora_fetch($Query_ID) ) {
    $next_id = ora_getcolumn($Query_ID, 0);
    }
    else {
    $next_id = 0;
    }
    if ( $Query_ID > 0 ) {
    ora_close($Query_ID);
    }

    return $next_id;
    }

    function disconnect() {
    if($this->Debug) {
    echo "Debug: Disconnecting $this->Query_ID...<br>n";
    }
    if ( $this->Query_ID < 1 ) {
    echo "<B>Warning</B>: disconnect(): Cannot free ID $this->Query_IDn";
    # return();
    }
    ora_close($this->Query_ID);
    $this->Query_ID=0;
    }

    /* private: error handling */
    function halt($msg) {
    if ($this->Halt_On_Error == "no")
    return;

    $this->haltmsg($msg);

    if ($this->Halt_On_Error != "report")
    die("Session halted.");
    }

    function haltmsg($msg) {
    printf("</td></tr></table><br><b>Database error:</b> %s<br>n", $msg);
    printf("<b>Oracle Error</b>: %s (%s)<br>n",
    $this->Errno,
    $this->Error);
    }

    function table_names() {
    $this->connect();
    $this->query("
    SELECT table_name,tablespace_name
    FROM user_tables");
    $i=0;
    while ($this->next_record())
    {
    $info[$i]["table_name"] =$this->Record["table_name"];
    $info[$i]["tablespace_name"]=$this->Record["tablespace_name"];
    $i++;
    }  
    return $info;
    }


    // Some transaction support
    // Methods are used in ct_oracle.inc
    function begin_transaction()  
    {
    $this->connect();
    // Now, disable autocommit
    Ora_CommitOff($this->Link_ID);
    if ($this->Debug)
    {
    print "BEGIN TRANSACTION<BR>";
    }
    }  
    function end_transaction()  
    {
    if ($this->Debug)
    {
    print "BEGIN TRANSACTION<BR>";
    }

    $res = 1;
    if(!@Ora_Commit($this->Link_ID))
    {
    Ora_CommitOn($this->Link_ID);
    $this->halt("Unable to finish transaction");
    $res = 0;
    }
    // Enable autocommit again
    Ora_CommitOn($this->Link_ID);

    if ($this->Debug)
    {
    print "END TRANSACTION : $res<BR>";
    }
    return $res;
    }


    }
    ?> 

    评论 {{userinfo.comments}}

    {{money}}

    {{question.question}}

    A {{question.A}}
    B {{question.B}}
    C {{question.C}}
    D {{question.D}}
    提交

    驱动号 更多