NTiProgramParameter
NTiProgramParameter décrit un paramètre d'appel de programme ou de procédure de programme de service : un buffer d'octets envoyé au serveur (InputData), un buffer rendu par le programme (OutputData), une direction et un CCSID. La classe est commune à CallProgram/CallProgramAsync et CallServiceProgram/CallServiceProgramAsync de NTiConnection.
Constructeurs
Tous acceptent une ParameterDirection optionnelle en dernier argument (défaut InputOutput).
| Constructeur | Type IBM i |
|---|---|
() |
récepteur VIDE à taille variable (voir plus bas) |
(string value, int length) |
CHAR(length), complété de blancs |
(string value, int length, int ccsid) |
CHAR(length) dans le CCSID donné |
(string[] values, int length) et variantes IEnumerable |
tableau de CHAR(length) |
(int value) / (int[] values) / (IEnumerable<int> values) |
BINARY(4) / tableau |
(short value) / (short[] values) / (IEnumerable<short> values) |
BINARY(2) / tableau |
(decimal value, int precision, int scale, bool packed = true) |
décimal packé (packed: true, DECIMAL) ou zoné (packed: false, NUMERIC) |
(byte[] value) |
octets bruts, envoyés tels quels |
Composition par Append
Les surcharges Append(...) prolongent le buffer du paramètre d'un champ supplémentaire, pour composer une structure de données dans un seul buffer ; chacune rend le paramètre, donc s'enchaîne.
| Surcharge | Champ ajouté |
|---|---|
Append(string, int) / Append(string, int, int ccsid) |
CHAR(length) |
Append(string[]/IEnumerable<string>, int) / idem avec ccsid |
tableau de CHAR(length) |
Append(int) / Append(int[]/IEnumerable<int>) |
BINARY(4) / tableau |
Append(short) / Append(short[]/IEnumerable<short>) |
BINARY(2) / tableau |
Append(decimal, int precision, int scale, bool packed = true) |
décimal packé ou zoné |
Append(byte[]) |
octets bruts |
Direction
Direction (défaut InputOutput) pilote ce qui circule ; les extensions fluides .AsInput(), .AsOutput(), .AsInputOutput() la posent en rendant le paramètre.
| Direction | Sémantique |
|---|---|
Input |
les octets sont envoyés, rien n'est rendu |
Output (et ReturnValue) |
seule la longueur est déclarée, le buffer revient dans OutputData |
InputOutput (défaut) |
les octets sont envoyés ET le buffer revient |
Extensions Add
La famille parms.Add(...) sur IListparms.Add("ABC", 10).AsInput(). Surcharges : Add() (récepteur vide), Add(string, int[, int ccsid]), Add(string[]/IEnumerable<string>, int[, int ccsid]), Add(int), Add(int[]/IEnumerable<int>), Add(short), Add(short[]/IEnumerable<short>), Add(decimal, int precision, int scale) (packé ; pour un zoné, passer par le constructeur), Add(byte[]) ; toutes avec la ParameterDirection optionnelle en dernier argument.
Lecture des résultats
Après l'appel, les accesseurs lisent le buffer de sortie (OutputData). Les entiers sont gros-boutistes (big endian), comme sur l'IBM i.
| Accesseur | Lit |
|---|---|
GetString() / GetString(int ccsid) |
tout le buffer en texte, dans le CCSID du paramètre ou un CCSID explicite |
GetString(int offset, int length) / GetString(int offset, int length, int ccsid) |
un segment en texte |
GetInt() / GetInt(int offset) |
BINARY(4) |
GetShort() / GetShort(int offset) |
BINARY(2), tel le préfixe de longueur d'un VARCHAR |
GetPackedDecimal(int precision, int scale[, int offset]) |
décimal packé |
GetZonedDecimal(int precision, int scale[, int offset]) |
décimal zoné |
GetBytes() / GetBytes(int offset, int length) |
octets bruts |
GetDTSTimestamp([int offset]) |
horodatage *DTS de 8 octets, rendu en DateTime |
InputData et OutputData sont des byte[] publics : le contrôle manuel intégral reste possible.
CCSID
| Membre | Rôle |
|---|---|
Ccsid |
CCSID du paramètre pour les conversions texte ; null = CCSID du job de l'appel |
NTiProgramParameter.DefaultCcsid (statique) |
défaut process-wide : 37 tant qu'aucune connexion n'est ouverte, puis CCSID de job de la DERNIÈRE connexion ouverte (compat v4) |
EffectiveCcsid |
CCSID effectif : l'explicite, sinon le défaut process-wide |
Avec plusieurs connexions sur des CCSID différents, passer un ccsid explicite (constructeur, Append ou GetString). Les caractères !, [, ], ^ varient d'une page EBCDIC à l'autre : expliciter le ccsid dès qu'ils comptent.
Récepteur vide
new NTiProgramParameter() (sans valeur) est un récepteur à taille variable : il est déclaré au serveur avec la longueur conventionnelle 0xFFFF sans émettre un octet, et revient dimensionné sur la donnée que le programme a réellement écrite (parité v4.4.14). C'est le pattern des sorties VARCHAR et des structures de réponse : receiver.GetString(2, receiver.GetShort()) lit un VARCHAR (préfixe de longueur BINARY(2), puis la donnée).
ServiceProgramParameterFormat
Propriété utilisée uniquement par CallServiceProgram/CallServiceProgramAsync (ignorée par CallProgram) : ByReference (défaut) passe l'adresse du stockage du paramètre ; ByValue passe un BINARY(4) par valeur, la donnée doit faire exactement 4 octets et la sortie n'a alors pas de sens. Valeurs dans NTiServiceProgramParameterFormat.
Contrat hexadécimal
Partout dans NTi, la représentation chaîne d'une donnée binaire est l'hexadécimal MAJUSCULE sans séparateur (parité v4) : c'est ce que rend le GetString du data reader sur une colonne BINARY, VARBINARY, ROWID ou taguée FOR BIT DATA (CCSID 65535). Sur un NTiProgramParameter, le binaire se lit avec GetBytes ou OutputData ; GetString exige un CCSID texte réel : demander 65535 (« pas de conversion ») lève une erreur explicite.
Exemple complet
L'async est la voie normale ; CallProgram existe aussi en synchrone.
using System;
using System.Collections.Generic;
using System.Data;
using System.Threading.Tasks;
using Aumerial.Data.Nti;
class ProgramParameterDemo
{
static async Task Main()
{
await using var connection = new NTiConnection("server=MYIBMI;user=MYUSER;password=MYPASSWORD");
await connection.OpenAsync();
// Structure d'entrée composée dans UN buffer par Append chaînés
var order = new NTiProgramParameter("CUST01", 10) // CHAR(10)
.Append(1042) // BINARY(4)
.Append(149.90m, 9, 2) // DECIMAL(9,2) packé
.Append("EUR", 3) // CHAR(3)
.AsInput();
// Récepteur VIDE : déclaré à taille variable, dimensionné sur la réponse
var reply = new NTiProgramParameter().AsInputOutput();
// Structure de sortie fixe de 30 octets
var ds = new NTiProgramParameter("", 30, ParameterDirection.Output);
var parms = new List { order, reply, ds };
parms.Add("*CURRENT", 10).AsInput(); // extension Add : crée, ajoute et rend
await connection.CallProgramAsync("MYLIB", "ORDERPGM", parms);
// Le récepteur vide contient un VARCHAR : préfixe de longueur, puis la donnée
string message = reply.GetString(2, reply.GetShort());
// Lecture par offsets dans la structure fixe
string code = ds.GetString(0, 10); // CHAR(10) à l'offset 0
int quantity = ds.GetInt(10); // BINARY(4) à l'offset 10
decimal total = ds.GetPackedDecimal(9, 2, 14); // DECIMAL(9,2) packé à l'offset 14
DateTime stamp = ds.GetDTSTimestamp(19); // horodatage *DTS à l'offset 19
Console.WriteLine($"{code} x{quantity} = {total} le {stamp:O} : {message}");
}
}