IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Oracle Discussion :

Oracle, Clob, procédures stockées, OCI_bind_by_name...


Sujet :

Oracle

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 23
    Points : 19
    Points
    19
    Par défaut [résolut]Oracle, Clob, procédures stockées, OCI_bind_by_name...
    Salut !

    Mon problème :

    Je veux passer une très grande chaine de charactère (php donc ilimitée) en paramètre d'une procédure stockée oracle (paramètre de type CLOB)

    voici l'appel de la fonction qui lance la procédure stockée oracle ($Strmotstexts représente la très grande chaine...)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $bdd->ProcStocDoc($Iddoc,$Idvers,$Idtype,$Libref,$Fichier->SaveFileNameExtLess,$Datedebval,$Datefinval,$Strmotscles,$Strauteurs,$Strmotstexts,$Strliens);
    voici la fonction qui lance la procédure stockée oracle :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    public function ProcStocDoc(&$Iddoc,&$Idvers,&$Idtype,&$Libref,&$Libdoc,&$Datedebval,
                                  &$Datefinval,&$Strmotscles,&$Strauteurs,&$Strmotstext,&$Strliens)
      {
          $requete = "BEGIN cre_document(:doc_no, :vers_no, :doc_type, :doc_ref, :doc_lib, :doc_datedebval,
                     :doc_datefinval, :doc_tabmotscles, :doc_tabauteurs, :doc_tabmotstext, :doc_tabliens); END;";
     
          $this->prepareRequete($requete);
     
          oci_bind_by_name($this->ressource1, ":doc_no", $Iddoc, 8);
          oci_bind_by_name($this->ressource1, ":vers_no", $Idvers, 10);
          oci_bind_by_name($this->ressource1, ":doc_type", $Idtype, 6);
          oci_bind_by_name($this->ressource1, ":doc_ref", $Libref, 20);
          oci_bind_by_name($this->ressource1, ":doc_lib", $Libdoc, 255);
          oci_bind_by_name($this->ressource1, ":doc_datedebval", $Datedebval, 10);
          oci_bind_by_name($this->ressource1, ":doc_datefinval", $Datefinval, 10);
          oci_bind_by_name($this->ressource1, ":doc_tabmotscles", $Strmotscles, 4000);
          oci_bind_by_name($this->ressource1, ":doc_tabauteurs", $Strauteurs, 4000);
          // Attention la liste des mots contenue dans le texte du document requiere un CLOB (4Go)...
          $clob = oci_new_descriptor($this->ressource, OCI_D_LOB);
          oci_bind_by_name($this->ressource1, ":doc_tabmotstext", $clob, -1, OCI_B_CLOB);     
          $clob->write($Strmotstext);
          oci_bind_by_name($this->ressource1, ":doc_tabliens", $Strliens, 4000);
          $this->executeRequete();
          $clob->free();  
      }

    Et enfin la procédure stockée elle même :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
     
    create or replace procedure CRE_DOCUMENT(
    doc_no IN OUT varchar2,
    vers_no IN OUT varchar2,
    doc_type IN varchar2,
    doc_ref IN varchar2,
    doc_lib IN varchar2,
    doc_datedebval IN varchar2,
    doc_datefinval IN varchar2,
    doc_tabmotscles IN varchar2,
    doc_tabauteurs IN varchar2,
    doc_tabmotstext IN CLOB,
    doc_tabliens IN varchar2) is
     
     
     chaine_motcle varchar2(4000);
     motcle varchar2(10);
     longueur number(10);
     pos number(10);
     
     
    begin
     
        /* CREATION DU DOCUMENT */
        select gdono into doc_no from gdidocument where gdolib = doc_lib;
        IF doc_no is not null THEN
              select SEQGDIDOC.nextval into doc_no from dual;
              IF doc_ref is not null THEN
                 IF doc_datefinval is not null THEN
                    insert into gdidocument values (doc_no,doc_type,doc_ref,doc_lib,doc_datedebval,doc_datefinval);
                 ELSE
                    insert into gdidocument values (doc_no,doc_type,doc_ref,doc_lib,doc_datedebval,null);
                 END IF;
              ELSE
                 IF doc_datefinval is not null THEN
                    insert into gdidocument values (doc_no,doc_type,null,doc_lib,doc_datedebval,doc_datefinval);
                 ELSE
                    insert into gdidocument values (doc_no,doc_type,null,doc_lib,doc_datedebval,null);
                 END IF; 
              END IF;
     
              /* ASSOCIATION DES MOTS CLES AVEC LE DOCUMENT CREE */
              IF (doc_tabmotscles is not null) THEN
                  chaine_motcle := doc_tabmotscles;
                  longueur := length(chaine_motcle);
                  WHILE longueur !=0 LOOP
                        pos := instr(chaine_motcle, ',');
                        IF pos != 0 THEN
                           motcle := substr(chaine_motcle,1,pos-1);
                           chaine_motcle := substr(chaine_motcle,pos+1,longueur);
                           longueur := length(chaine_motcle);                   
                        ELSE
                           motcle := substr(chaine_motcle,1,longueur);
                        END IF;
                        insert into gdidisposer values(doc_no,motcle);
                  END LOOP;         
              END IF; 
     
              /* CREATION DE LA PREMIERE VERSION ASSOCIE AU DOCUEMNT */
              cre_version(vers_no,doc_no,doc_tabauteurs,doc_tabmotstext,doc_tabliens);         
     
        END IF;
     
     
        COMMIT WORK;
     
     
     
    end CRE_DOCUMENT;
    A l'execution j'ai l'erreur suivante qui s'affiche :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Warning: OCI-Lob::write() [function.write]: OCILobGetLength: OCI_INVALID_HANDLE in C:\www\monsite\include\oracle.class.php on line 169
    Et bien sûr une erreur oci_execute() qui en découle...

    Je pense que le problème vient de la fonction ci_new_descriptor qui ne créer pas le clob...


    HELP ME Please !! Je suis désespérer...


    PS: Apache/2.0.54 (Win32) PHP/5.0.5 Oracle9i

    Essai sous Firefox
    Editeur PSPad

  2. #2
    Membre habitué
    Inscrit en
    Octobre 2005
    Messages
    125
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 125
    Points : 125
    Points
    125
    Par défaut
    De ce que je vois
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $clob = oci_new_descriptor($this->ressource, OCI_D_LOB);
    il te manque un "1" dans ta ressource...

    Au passage, c ptet plus dans le forum PHP qu'il faudrait poster ?

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 23
    Points : 19
    Points
    19
    Par défaut
    Yep !

    this->ressource correspond à la connexion
    this->ressource1 correspond à la requête "parser"...

    Désolé c'est pas moi qui ai fait la classe oracle c'est un collègue (var a, var b... j'aime pas non plus mais je veux surtout pas le vexer donc je fais avec...)

    J'ai mis le sujet dans les deux sections.

    P.S. : Pourtant j'ai suivi à la lettre (enfin j'espère) l'exemple donné par PHP.net...

  4. #4
    Membre habitué
    Inscrit en
    Octobre 2005
    Messages
    125
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 125
    Points : 125
    Points
    125
    Par défaut
    Pour ma part (je suis en train de bosser sur du php pour l'insertion de CLOB ), j'ai suivi la methode oci-new-descriptor.
    Cependant je bosse avec un INSERT/UPDATE, j'ai pas encore teste avec une procedure.

    En tout cas je me souviens que j'avais cette erreur lorsque je faisais une requete du genre.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    insert into $table (id, the_clob) 
    values(my_seq.NEXTVAL, :the_clob)
    Par la suite j'ai suivi correctement l'exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    insert into $table (id, the_clob) 
    values(my_seq.NEXTVAL, EMPTY_XLOB()) returning the_xlob into :the_clob
    Et ca marchait beaucoup mieux.

    A mon avis commence deja a inserer ton clob (meme avec juste qques caracteres) a travers ta procedure et de verifier que ca marche.
    Je vais essayer ce soir de creer cette procedure et voir ce que cela me donne...

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 23
    Points : 19
    Points
    19
    Par défaut
    Merci pour ton aide tostini...

    Donc ça donnerait ça ? :

    $clob->write("Bla,Bla,Toto,titi,kiki,et compagnie");

    Malheureusement j'ai déjà essayé et la même erreur survient...

    A mon avis le clob n'est pas initialisé..
    ce que tu fais avec EMPTY_CLOB(). Mais dans le cas d'une procédure stockée ???

    Peut-être faut-il que je crée une table tampon pour pouvoir stocker le clob...


    A titre indicatif, l'exemple fourni par php.net :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    <?php 
       /* Calling PL/SQL stored procedures which contain clobs as input
         * parameters (PHP 4 >= 4.0.6).
         * Example PL/SQL stored procedure signature is:
         *
         * PROCEDURE save_data
         *  Argument Name                  Type                    In/Out Default?
         *  ------------------------------ ----------------------- ------ --------
         *  KEY                            NUMBER(38)              IN
         *  DATA                          CLOB                    IN
         *
         */
     
       $conn = oci_connect($user, $password);
       $stmt = oci_parse($conn, "begin save_data(:key, :data); end;");
       $clob = oci_new_descriptor($conn, OCI_D_LOB);
       oci_bind_by_name($stmt, ':key', $key);
       oci_bind_by_name($stmt, ':data', $clob, -1, OCI_B_CLOB);
       $clob->write($data);
       oci_execute($stmt, OCI_DEFAULT);
       oci_commit($conn);
       $clob->free();
       oci_free_statement($stmt);
    ?>

  6. #6
    Membre habitué
    Inscrit en
    Octobre 2005
    Messages
    125
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 125
    Points : 125
    Points
    125
    Par défaut
    Youhou.
    Bon je pense que j'ai ta solution
    En fait comme on le commentait, l'exemple de la doc php.net est doublement faux

    Donc voila ce qu'il faut faire...
    Tout d'abord, il faut executer la requete avant de faire quoi que ce soit avec ton clob. Enfin il faut que ta procedure accepte le parametre CLOB en tant que OUT et que justement tu fasses de la meme maniere qu'avec mon INSERT/UPDATE, a savoir, utiliser une clause RETURNING.

    Voici le code qui va bien.
    Desole pour le PHP, mais je pense que ca peux servir a tout le monde

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    CREATE TABLE MA_TABLE ( 
      MON_CLOB  CLOB ) ; 
     
    --la procedure d'exemple
    CREATE OR REPLACE PROCEDURE SAVE_DATA(LE_CLOB OUT CLOB) IS
    BEGIN
    	 INSERT INTO MA_TABLE (MON_CLOB) VALUES (EMPTY_CLOB()) RETURNING MON_CLOB INTO LE_CLOB;
    END;
     
    --le php qui va bien
    $data = '1234568790';
    $conn = oci_connect($user, $password); 
     
    $stmt = oci_parse($conn, "begin save_data(:data); end;"); 
    $clob = oci_new_descriptor($conn, OCI_D_LOB);
    oci_bind_by_name($stmt, ":data", $clob, -1, OCI_B_CLOB); 
    oci_execute($stmt, OCI_DEFAULT); 
    $clob->write($data); 
    oci_commit($conn); 
    $clob->free(); 
    oci_free_statement($stmt);
    Et voila un joli clob insere dans ma table.

    Pour plus d'infos, regarde cet example d'Oracle.
    Calling Oracle Stored Procedures with PHP
    Au passage c chouette car du coup ca m'a aider a comprendre les CLOBs Merci

    PS : un ti rapport de bug : http://bugs.php.net/bug.php?id=32859

  7. #7
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 23
    Points : 19
    Points
    19
    Par défaut
    Citation Envoyé par nguthans
    Peut-être faut-il que je crée une table tampon pour pouvoir stocker le clob..
    Arf je m'en doutais un peu...

    Pour l'instant, j'ai utilisé un varchar2 ce qui limite mon application à environ 400 mots indexés par fichier. C'est pas trop mal, mais si un gros fichier de quelques Mo est archivé... Enfin en moyenne ce sont des fichiers texte de 5 pages avec (après tri) 250 - 300 mots efficaces pour une recherche textuel.

    Sinon il y a aussi la solution des tableaux de varchar2 sous oracle. En déclarant un type perso qui sera utilisé pour les paramètres des procédures stockées. Mais je sais pas pourquoi, je sens que lier un tableau PHP avec le tableau (perso.) oracle ne va pas être simple non plus...

    Bon pour l'instant je ne marque pas le sujet [Résolu], faut d'abord que je teste avec le clob...

    Encore merci tostinni...


  8. #8
    Membre habitué
    Inscrit en
    Octobre 2005
    Messages
    125
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 125
    Points : 125
    Points
    125
    Par défaut
    Ton message me fait penser a un truc...
    Tu parles d'un index de mots, ce n'est pas ca que tu veux mettre ds une seule colonne nan ?
    Car si c'est vraiment le cas, je pense qu'une table fille de tes documents serait bcp plus efficace pour une recherche avec un mot par registre ainsi tu pourras utiliser un index sur ta colonne plutot que de faire un "FULL SCAN" sur ta table

  9. #9
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 23
    Points : 19
    Points
    19
    Par défaut
    Résolu : pour utiliser un clob en php dans une procédure stockée (paramètre IN) il faut un code php du type
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    $clob = oci_new_descriptor($conn, OCI_D_LOB);
    $stmt = oci_parse($conn, "begin save_data(:data); end;"); 
    oci_bind_by_name($stmt, ":data", $clob, -1, OCI_B_CLOB);
    $clob->writeTemporary($Strmotstext);
    oci_execute($stmt, OCI_DEFAULT);
    $clob->close();
    $clob->free(); 
    oci_free_statement($stmt);
    ex : genre de code pl/sql qu'on pourrait avoir
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
    CREATE OR REPLACE PROCEDURE SAVE_DATA(LE_CLOB IN CLOB) IS
    buffer_stream varchar2(10);
    l_buffer  VARCHAR2(1);
    l_amount  BINARY_INTEGER := 1;
    l_pos     INTEGER := 1;
    BEGIN
            --INSERT INTO ma_table (mon_clob) VALUES (le_clob);
           BEGIN
               LOOP
                  --exploiter LE_CLOB
                  DBMS_LOB.read (LE_CLOB, l_amount, l_pos, l_buffer);
                    DBMS_OUTPUT.PUT(l_buffer);
                    l_pos := l_pos + l_amount;
               END LOOP;
           EXCEPTION -- A la fin du CLOB on rencontre une erreur
               WHEN NO_DATA_FOUND THEN
               NULL;
           END;
    END;
    NB : je n'ai plus vérifié ces codes là, je les ai réécris à la volée pour correspondre au suivi du post

    En fait ce qui est essentiel, c'est d'utiliser la fonction $clob->writeTemporary quand on utilise un clob en IN dans une procédure stockée (>>prob dans la doc php qui indique la fonction write et évidemment ça ne marche pas dans ce cas là, mais uniquement pour le cas de tostinni
    IL nous fallait exploiter un clob mais pas l'insérer dans un champ d'une table sinon le code de tostinni nous aurait suffit (même si on peut également le faire depuis le code précédent)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     
    CREATE TABLE MA_TABLE ( 
      MON_CLOB  CLOB ) ; 
     
    --la procedure d'exemple
    CREATE OR REPLACE PROCEDURE SAVE_DATA(LE_CLOB OUT CLOB) IS
    BEGIN
    	 INSERT INTO MA_TABLE (MON_CLOB) VALUES (EMPTY_CLOB()) RETURNING MON_CLOB INTO LE_CLOB;
    END;
     
    --le php qui va bien
    $data = '1234568790';
    $conn = oci_connect($user, $password); 
     
    $stmt = oci_parse($conn, "begin save_data(:data); end;"); 
    $clob = oci_new_descriptor($conn, OCI_D_LOB);
    oci_bind_by_name($stmt, ":data", $clob, -1, OCI_B_CLOB); 
    oci_execute($stmt, OCI_DEFAULT); 
    $clob->write($data); 
    oci_commit($conn); 
    $clob->free(); 
    oci_free_statement($stmt);

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Oracle - Firebird, procédures stockées
    Par zorino dans le forum Oracle
    Réponses: 2
    Dernier message: 25/10/2006, 19h58
  2. [Oracle] Oracle, Clob, procédures stockées, OCI_bind_by_name...
    Par nguthans dans le forum PHP & Base de données
    Réponses: 1
    Dernier message: 03/03/2006, 11h20
  3. Executer procédure stockée base oracle ADOStoredProc
    Par Akei dans le forum Bases de données
    Réponses: 2
    Dernier message: 21/06/2004, 09h46
  4. procédure stockée Oracle dans delphi 6
    Par UPNE387 dans le forum Bases de données
    Réponses: 3
    Dernier message: 04/05/2004, 10h47
  5. Réponses: 12
    Dernier message: 27/08/2003, 12h04

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo