简体   繁体   中英

SQL Server INSERT query with ODBC & PHP : weird syntax error

I have a PHP webpage running a few SQL queries in a transaction, to be writted in a SQL Server 2008 R2 database. The production server uses:

  • PHP 5.3 32 bits
  • ODBC SQL Server Driver 32 bits version 6.01
  • IIS 7.5

Everything works fine on this environment.

I have to upgrade to PHP 7.3 64 bits on a new Windows Server 2016 server, running IIS 10 and a more recent SQL Server ODBC driver (64 bits). I tried to run the same page but one of the queries doesn't work:

INSERT INTO LIGNELIVRAISON 
(ARTICLEID, LCDEID, LIVID, LIGNELIVQTELIV, LIGNELIVDATECREATION, LIGNELIVQTEINITIALE, LIGNELIVMTUNITHT, LIGNELIVMTUNITTVA, LIGNELIVMTUNITTTC, LIGNELIVMTREMISE, LIGNELIVCODELOT, LIGNELIVDATEPEREMPTION) 
VALUES 
(1573, 44551, 35232, 3, CONVERT(datetime, '27/09/2019 13:48:54'), 3, 50, 4.25, 54.25, 0, '???', CONVERT(date, '31/12/2050'));

The error message is:

Code 37000: [Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error near '*='.

The characters "*=" aren't anywhere in this query, as we can see. I tried multiple versions of PHP (5 or 7), multiple and more recent ODBC drivers, but I always get the same result when I run this query through the odbc_exec() function.I tried using PDO or sqlsrv functions, but the outcome is the same.

If I try to copy/paste this query in SQL Server Management Studio, it works fine.

I think it might be related to the ODBC driver, but I can't install the same one that is currently in production because it doesn't work on Windows 2016 and it is a 32 bits driver. I tried running a 32-bits version of PHP 7.3 to no avail.

Part of the PHP code:

$ms->hdebug();
    //$ms->libre('SET IMPLICIT_TRANSACTIONS OFF');
    //$ms->libre('BEGIN TRANSACTION');
    odbc_autocommit($ms->get_lien(), false);

    $id_utilisateur_creation = id_utilisateur_athome($my, $ms);

    // On a ajouté un contrôle en amont mais par sécurité, on ajoute un contrôle ici
    if ($id_utilisateur_creation === FALSE) {
      $id_utilisateur_creation = 1;
    }

    // 25 = Fournisseur matériel
    $id_type_intervenant = 25; 
    $type_facture = 'F';
    // 2 = Location
    $id_type_produit = 2;
    // 5 = Livrée
    $id_etat_commande = 5;
    $franco_port = 'N';
    $tproduitcode = 'LOCA';
    $date = date('d/m/Y');
    $date_heure = date('d/m/Y H:i:s');
    $montant_remise = 0;
    $total_ttc = 0;
    $etat_sejour_suivi = 14;
    // Pour éviter une erreur lors de l'insertion des lignes de livraison, liées a une procédure stockée
    $code_lot_article = '???';
    $date_peremption_article = '31/12/2050';
    $commentaires = addslashes('Commande créée pour le bon de location n° ' . $_POST['id_location']);

    // Récupération des TVA AtHome
    $tva_athome = $ms->lire(
      'TVAID, TVATAUX * 100',
      'TVA',
      "AND TVAVISIBLE = 'O'",
      "TVATAUX ASC"
    );

    $mapping_tva = array();

    foreach($tva_athome as $tva) {
      list($id_tva, $taux_tva) = $tva;
      $mapping_tva[$id_tva] = round($taux_tva, 2);
    }
    // -

    // Etape 1: Création de la commande et lignes de commande
    $id_commande = $ms->ajouter(
      'CDEFRN',
      'UTIID, TPRODUITID, FOURNID, ETATCDEID, PATID,
       CDEFRNDATE, CDEFRNFRANCOPORT, CDEFRNDATECREATION, TProduitCode, CDEFRNCOMMENTAIRE',
      "$id_utilisateur_creation, $id_type_produit, {$_POST['id_fournisseur']}, $id_etat_commande, {$_POST['ipp']},
       CONVERT(date, '$date'), '$franco_port', CONVERT(datetime, '$date_heure'), '$tproduitcode', '$commentaires'"
    );

    $lignes_commande = array();

    // Ajout des lignes d'articles
    foreach($_POST['articles'] as $id_article) {
      if ($_POST['prix'][$id_article] > 0 && $_POST['quantite'][$id_article] > 0) {
        $quantite = $_POST['quantite'][$id_article];
        $taux_tva = $mapping_tva[$_POST['tva'][$id_article]];
        $prix_ht = round($_POST['prix'][$id_article], 2);
        // On calcule les arrondis ici pour ne pas avoir de problème d'arrondi dans AtHome à cause des champs de type money
        $prix_ttc = round($prix_ht * (1 + ($taux_tva / 100)), 2);
        $montant_tva = $prix_ttc - $prix_ht;

        $lignes_commande[$id_article] = $ms->ajouter(
          'LIGNECDEFRN',
          'CDEFRNID, ARTICLEID, LCDEQTECDE, LCDEMTHT, LCDEMTTVA,
           LCDEMTTTC, LCDEMTREMISE, LCDEDATECREATION, LCDEQTEINITIALE',
          "$id_commande, $id_article, $quantite, $prix_ht, $montant_tva,
           $prix_ttc, $montant_remise, CONVERT(datetime, '$date_heure'), $quantite"
        );

        $total_ttc += $prix_ttc;
      }
    }

    $total_ttc = round($total_ttc, 2);

    // Etape 2: Livraison
    $id_livraison = $ms->ajouter(
      'LIVRAISON',
      'CDEFRNID, LIVDATE, LIVDATECREATION',
      "$id_commande, CONVERT(date, '$date'), CONVERT(datetime, '$date_heure')"
    );

    $lignes_livraison = array();

    // Ajout des lignes de livraison
    foreach($_POST['articles'] as $id_article) {
      if ($_POST['prix'][$id_article] > 0 && $_POST['quantite'][$id_article] > 0) {
        $quantite = $_POST['quantite'][$id_article];
        $taux_tva = $mapping_tva[$_POST['tva'][$id_article]];
        $prix_ht = round($_POST['prix'][$id_article], 2);
        // On calcule les arrondis ici pour ne pas avoir de problème d'arrondi dans AtHome à cause des champs de type money
        $prix_ttc = round($prix_ht * (1 + ($taux_tva / 100)), 2);
        $montant_tva = $prix_ttc - $prix_ht;

        $lignes_livraison[$id_article] = $ms->ajouter(
          'LIGNELIVRAISON',
          'ARTICLEID, LCDEID, LIVID, LIGNELIVQTELIV, LIGNELIVDATECREATION,
           LIGNELIVQTEINITIALE, LIGNELIVMTUNITHT, LIGNELIVMTUNITTVA, LIGNELIVMTUNITTTC, LIGNELIVMTREMISE,
           LIGNELIVCODELOT, LIGNELIVDATEPEREMPTION',
          "$id_article, {$lignes_commande[$id_article]}, $id_livraison, $quantite, CONVERT(datetime, '$date_heure'),
           $quantite, $prix_ht, $montant_tva, $prix_ttc, $montant_remise,
           '$code_lot_article', CONVERT(date, '$date_peremption_article')"
        );
      }
    }
public function ajouter($table,$champs,$valeurs)
    {
      if(trim($champs)=="")
      {
        $req="INSERT INTO ".$table." VALUES(".$valeurs.");";
      }
      else
      {
        $req="INSERT INTO ".$table." (".$champs.") VALUES(".$valeurs.");";
      }
      $retour=-1;
      if($this->hdebug)
      {
        $this->log->logguer("INS",$req);
      }
      if($this->debug)
      {
        echo "<debug_sql>".$req."</debug_sql>";
      }
      else
      {
        if($this->calcul_temps)
        {
          $_SESSION["Temps_Execution"]->Debut_Compter("MsSQL");
        }
        //$res = @mssql_query($req,$this->lien) or $this->erreur("insert",$req,0,"");
        //$res = odbc_prepare($this->lien, $req);
        //$res_ex = odbc_execute($res);

        $res = odbc_exec($this->lien, $req);

        if (!$res) {
          //var_dump($req);
          $this->erreur("insert", $req, odbc_error($this->lien), odbc_errormsg($this->lien));
        }

        $id_retour=@odbc_exec($this->lien,"SELECT @@IDENTITY") or $this->erreur("insert",$req,0,"");
        $retour=odbc_result($id_retour, 1);
        if($this->calcul_temps)
        {
          $_SESSION["Temps_Execution"]->Fin_Compter("MsSQL");
        }
        //$retour=mysql_insert_id($this->lien);
      }
      //$retour=0;
      return $retour;
    }

EDIT: The FR datetime format in the queries works fine. Issue isn't related to it at all, I think.

You need to pass correct date time format (ie: MM/dd/yyyy hh:mm:ss). Because SQL Server by default understand US date time standard.

Please check below select query.

SELECT 
    CONVERT(date, '12/31/2050') LIGNELIVDATEPEREMPTION,
    CONVERT(datetime, '09/27/2019 13:48:54') LIGNELIVDATECREATION

Please check below insert script for your answer.

INSERT INTO LIGNELIVRAISON 
(ARTICLEID, LCDEID, LIVID, LIGNELIVQTELIV, LIGNELIVDATECREATION, LIGNELIVQTEINITIALE, LIGNELIVMTUNITHT, LIGNELIVMTUNITTVA, LIGNELIVMTUNITTTC, LIGNELIVMTREMISE, LIGNELIVCODELOT, LIGNELIVDATEPEREMPTION) 
VALUES 
(1573, 44551, 35232, 3, CONVERT(datetime, '09/27/2019 13:48:54'), 3, 50, 4.25, 54.25, 0, '???', CONVERT(date, '12/31/2050'));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM