web-dev-qa-db-fra.com

Qu'est-ce que cela signifie lorsque Statement.executeUpdate () renvoie -1?

Une requête qui fonctionne dans le studio de gestion et dans le executeUpdate fait que le même executeUpdate retourne -1, qui n'est pas défini dans la documentation que nous pouvons trouver. Il est censé renvoyer uniquement le nombre de lignes ou 0. Qu'est-ce que ça veut dire? Le pilote est le pont JDBC-ODBC si cela importe.

Exemple:

String query = "IF NOT EXISTS (SELECT * FROM animals WHERE animal_name ='" + a +"') INSERT INTO " + table + " (animal_name, animal_desc, species_id) VALUES ('" + a + "', '" + b + "', " + c + ")";
int result = statement.executeUpdate(query);
System.out.println(result);

La requête fonctionne, car la ligne est ajoutée à la base de données, il est tout simplement étrange qu'elle renvoie -1 où la documentation indique qu'elle ne renverra que 0 ou le nombre de lignes (comme j'ai été corrigé).

MISE À JOUR:

L'exécution de cela dans Management Studio entraîne la "Commande terminée avec succès".

IF NOT EXISTS (SELECT * FROM animals WHERE animal_name = 'a') 
INSERT INTO animals(animal_name, animal_desc, species_id) VALUES ('a', 'a', 1)

Cela devrait signifier que la méthode doit retourner 0 car elle ne renvoie rien, n'est-ce pas?

26
ldam

Donc 4 ans plus tard, Microsoft a ouvert son pilote JDBC sur Github . J'ai reçu une notification à propos de cette question aujourd'hui, et je suis allé voir, et je crois que j'ai trouvé le coupable ici , mssql-jdbc/src/main/Java/com/Microsoft/sqlserver/jdbc/SQLServerStatement.Java:1713.

Fondamentalement, le pilote essaie de comprendre ce que SQL Server renvoie s'il ne s'agit pas d'un jeu de résultats défini. Selon les commentaires, cela se passe comme suit:

  1. Vérifiez d'abord les erreurs. (ln 1669)

  2. Pas une erreur. Est-ce un jeu de résultats? (ln 1680)

  3. Pas une erreur ou un ensemble de résultats. Peut-être un résultat d'une instruction T-SQL? Autrement dit, l'un des éléments suivants:

    • un décompte positif du nombre de lignes concernées (à partir de INSERT, UPDATE ou DELETE),
    • un zéro indiquant qu'aucune ligne n'est affectée, ou que l'instruction était DDL, ou
    • a -1 indiquant que l'instruction a réussi, mais il n'y a pas d'informations de compte de mise à jour disponibles (se traduit par Statement.SUCCESS_NO_INFO dans les tableaux de comptage de mise à jour par lots). (ln 1706)
  4. Aucune de ces réponses. Dernière chance ici ... En entrant dans l'analyseur ci-dessus, nous savons que plusRésultats était initialement vrai. Si nous sortons avec moreResults false, nous frappons un jeton DONE (DONE (FINAL) ou DONE (RPC en lot)) qui indique que le lot a réussi dans l'ensemble, mais qu'il n'y a aucune information sur le nombre de mises à jour des instructions individuelles. Ceci est similaire au dernier cas ci-dessus, sauf qu'il n'y a pas de compte de mise à jour. C'est-à-dire: nous avons un résultat réussi (return true), mais nous n'avons aucune autre information à ce sujet (updateCount = -1). (en 1693)

  5. Le seul moyen d'arriver ici (moreResults est toujours vrai, mais aucun résultat apparent d'aucune sorte) est si le TDSParser n'a pas réellement analysé n'importe quoi. Autrement dit, nous sommes à EOF dans la réponse. Dans ce cas, il n'y a vraiment plus de résultats. Nous avons terminé. (Ln 1717)

(Souligner le mien)

Donc vous aviez raison à la fin. SQL ne peut tout simplement pas dire combien de lignes sont affectées, et par défaut à -1. :)

7
ldam

Comme l'instruction exécutée n'est pas réellement DML (par exemple UPDATE, INSERT ou EXECUTE), mais un morceau de T-SQL qui contient DML, je soupçonne qu'il n'est pas traité comme une mise à jour-requête.

La section 13.1.2.3 de la spécification JDBC 4.1 indique quelque chose (plutôt difficile à interpréter btw):

Lorsque la méthode execute renvoie true, la méthode getResultSet est appelée pour récupérer l'objet ResultSet. Lorsque execute renvoie false, la méthode getUpdateCount renvoie un int. Si ce nombre est supérieur ou égal à zéro, il indique le nombre de mises à jour renvoyé par l'instruction. Si c'est -1, cela indique qu'il n'y a plus de résultats.

Compte tenu de ces informations, je suppose que executeUpdate() fait en interne une execute(), puis - comme execute() renverra false - il renverra la valeur de getUpdateCount(), qui dans ce cas - conformément à la spécification JDBC - renverra -1.

Ceci est encore corroboré par le fait 1) que le Javadoc pour Statement.executeUpdate() dit:

Renvoie: (1) le nombre de lignes pour les instructions SQL Data Manipulation Language (DML) ou (2) 0 pour les instructions SQL qui ne renvoient rien

Et 2) que le Javadoc pour Statement.getUpdateCount () spécifie:

le résultat actuel en tant que compte de mise à jour; -1 si le résultat actuel est un objet ResultSet ou s'il n'y a plus de résultats

Juste pour clarifier: étant donné la Javadoc pour executeUpdate() le comportement est probablement faux, mais il peut être expliqué.

Aussi comme je l'ai commenté ailleurs, le -1 pourrait simplement indiquer: peut-être que quelque chose a été changé, mais nous ne savons tout simplement pas, ou nous ne pouvons pas donner un nombre précis de changements (par exemple parce que dans cet exemple, c'est un morceau de T- SQL exécuté).

27
Mark Rotteveel

Pour les instructions executeUpdate sur un serveur DB2 for z/OS, la valeur renvoyée dépend du type d'instruction SQL en cours d'exécution:

Pour une instruction SQL qui peut avoir un nombre de mises à jour, telle qu'une instruction INSERT, UPDATE ou DELETE, la valeur renvoyée est le nombre de lignes affectées. Ça peut être:

Un nombre positif, si un nombre positif de lignes est affecté par l'opération et que l'opération n'est pas une suppression en masse sur un espace table segmenté.

0, si aucune ligne n'est affectée par l'opération.

- 1, si l'opération est une suppression en masse sur un espace table segmenté.

Pour une instruction DB2 CALL, une valeur de -1 est renvoyée, car le serveur de base de données DB2 ne peut pas déterminer le nombre de lignes affectées. Les appels à getUpdateCount ou getMoreResults pour une instruction CALL renvoient également -1. Pour toute autre instruction SQL, une valeur de -1 est renvoyée.

5
Sachin Mhetre

Je n'ai vu cela nulle part non plus, mais mon instinct serait que cela signifie que le IF a empêché la totalité de l'instruction de s'exécuter.

Essayez d'exécuter l'instruction avec une base de données où passe le IF.

Vérifiez également s'il y a des déclencheurs impliqués qui pourraient changer le résultat.

[EDIT] Lorsque la norme dit que cette fonction ne doit jamais retourner -1, ce n'est pas appliquer ceci. Java n'a pas de conditions de pré et post. Un pilote JDBC pourrait retourner un nombre aléatoire et il n'y avait aucun moyen de l'arrêter.

S'il est important de savoir pourquoi cela se produit, exécutez l'instruction sur une base de données différente jusqu'à ce que vous ayez essayé tous les chemins d'exécution (c'est-à-dire celui où IF renvoie false et l'autre où il renvoie true).

Si ce n'est pas si important, marquez-le comme un "truc astucieux" par un ingénieur Microsoft et rappelez-vous combien vous avez aimé quand vous avez envie d'être intelligent vous-même la prochaine fois.

5
Aaron Digulla

Cela n'explique pas pourquoi cela devrait être comme ça, mais cela explique pourquoi cela pourrait arriver. Les jeux de codes d'octets suivants -1 au drapeau interne updateCount dans le constructeur SQLServerStatement:

// Method descriptor #401 (Lcom/Microsoft/sqlserver/jdbc/SQLServerConnection;II)V
// Stack: 5, Locals: 8
SQLServerStatement(
  com.Microsoft.sqlserver.jdbc.SQLServerConnection arg0, int arg1, int arg2) 
throws com.Microsoft.sqlserver.jdbc.SQLServerException;

// [...]

34 aload_0 [this]
35 iconst_m1
36 putfield com.Microsoft.sqlserver.jdbc.SQLServerStatement.updateCount:int [27]

Maintenant, je n'analyserai pas tous les flux de contrôle possibles, mais je dirais simplement que c'est la valeur d'initialisation par défaut interne qui s'échappe d'une manière ou d'une autre dans le code client. Notez que cela se fait également dans d'autres méthodes:

// Method descriptor #383 ()V
// Stack: 2, Locals: 1
final void resetForReexecute() 
throws com.Microsoft.sqlserver.jdbc.SQLServerException;

// [...]

10 aload_0 [this]
11 iconst_m1
12 putfield com.Microsoft.sqlserver.jdbc.SQLServerStatement.updateCount:int [27]

// Method descriptor #383 ()V
// Stack: 3, Locals: 3
final void clearLastResult();
0 aload_0 [this]
1 iconst_m1
2 putfield com.Microsoft.sqlserver.jdbc.SQLServerStatement.updateCount:int [27]

En d'autres termes, vous êtes probablement une interprétation sûre -1 comme étant identique à 0. Si vous comptez sur cette valeur de résultat, restez peut-être du bon côté et effectuez vos vérifications comme suit:

// No rows affected
if (stmt.executeUpdate() <= 0) {
}
// Rows affected
else {
}

[~ # ~] mise à jour [~ # ~] : En lisant réponse de Mark Rotteveel , j'ai tendance à être d'accord avec lui, en admettant que -1 est la valeur conforme à JDBC pour "nombre de mises à jour inconnues". Même si cela n'est pas documenté sur le Javadoc de la méthode appropriée, il est documenté dans le Spécifications JDBC, chapitre 13.1.2.3 Renvoi de résultats inconnus ou multiples . Dans ce cas précis, on pourrait dire qu'un IF .. INSERT .. l'instruction aura un "nombre de mises à jour inconnues", car cette instruction n'est pas conforme au standard SQL de toute façon.

4
Lukas Eder