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 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
| //------------------------------------------------------------------------------
function TSLTODACSQLGenerator.InsertPrepare(const ATableName: string; const AFieldValueNames: array of string; const AParamValueNames: array of string; const AParamValueDataTypes: array of TFieldType; const AKeyFieldNames: array of string): Boolean;
const
SQL_INSERT_FMT = 'INSERT INTO %s (%s) VALUES(%s)'; // Do not localize
PLSQL_INSERT_WITH_COMPOSITE_FMT = 'BEGIN %s RETURNING %s INTO %s; :%s := SQL%%ROWCOUNT; END;';
PLSQL_INSERT_NO_KEYS_FMT = 'BEGIN %s; :%s := SQL%%ROWCOUNT; END;';
var
KeyName: string;
Returns: TStringList;
Fields: TStringList;
Params: TStringList;
I, ipn: Integer;
InsertSQL: string;
InsertPLSQL: string;
Param: ISLTDBQueryParameter;
OutParamNames: array of string;
begin
// La Query doit être initialisée
if not Assigned(FQueryEngine) or not Assigned(FQueryEngine.Query) then
raise ESLTDBQuerySQLGeneratorError.CreateFmt(ERR_EMPTY_ERROR_FMT, [IN_COMPOSITE, MN_QUERY, FN_INSERT_PREPARE]); // Pseudo-Assert Exception !
FQueryEngine.UnPrepare();
// Le nom de la table est obligatoire
if ATableName = '' then
raise ESLTDBQuerySQLGeneratorError.CreateFmt(ERR_EMPTY_ERROR_FMT, [IN_COMPOSITE, PN_TABLE_NAME, FN_INSERT_PREPARE]); // Pseudo-Assert Exception !
// Value contient les noms des champs dont les valeurs seront insérées en Base
if Length(AFieldValueNames) <= 0 then
raise ESLTDBQuerySQLGeneratorError.CreateFmt(ERR_EMPTY_ERROR_FMT, [IN_COMPOSITE, PN_FIELD_NAME, FN_INSERT_PREPARE]); // Pseudo-Assert Exception !
// Pour chaque nom de champs, il faut un nom de paramètre. Utilise le même ordre
if Length(AParamValueNames) <> Length(AFieldValueNames) then
raise ESLTDBQuerySQLGeneratorError.CreateFmt(ERR_ARRAY_ERROR_FMT, [IN_COMPOSITE, PN_FIELD_NAME, PN_PARAM_NAME, FN_INSERT_PREPARE]); // Pseudo-Assert Exception !
// Pour chaque nom de paramètre, il faut un type de paramètre. Utilise le même ordre
if Length(AParamValueNames) <> Length(AParamValueDataTypes) then
raise ESLTDBQuerySQLGeneratorError.CreateFmt(ERR_ARRAY_ERROR_FMT, [IN_COMPOSITE, PN_PARAM_NAME, PN_PARAM_DATA_TYPE, FN_INSERT_PREPARE]); // Pseudo-Assert Exception !
// Génération du SQL INSERT
Fields := TStringList.Create();
try
Fields.Capacity := Length(AFieldValueNames);
Params := TStringList.Create();
try
Params.Capacity := Length(AParamValueNames);
for I := Low(AFieldValueNames) to High(AFieldValueNames) do
begin
Fields.Add(AFieldValueNames[I]);
Params.Add(INTERNAL_PARAM_MARK + AParamValueNames[I]);
end;
InsertSQL := Format(SQL_INSERT_FMT, [ATableName, Fields.CommaText, Params.CommaText]);
finally
Params.Free();
end;
finally
Fields.Free();
end;
// Génération du PL/SQL encapsulant le INSERT
if Length(AKeyFieldNames) > 0 then
begin
Params := TStringList.Create();
try
Params.Capacity := Length(AKeyFieldNames);
Returns := TStringList.Create();
try
Returns.Capacity := Length(AKeyFieldNames);
SetLength(OutParamNames, Length(AKeyFieldNames));
for I := Low(AKeyFieldNames) to High(AKeyFieldNames) do
begin
KeyName := AKeyFieldNames[I];
ipn := IndexStr(KeyName, AFieldValueNames);
if ipn >= 0 then
begin
Returns.Add(KeyName);
Params.Add(INTERNAL_PARAM_MARK + AParamValueNames[ipn]);
OutParamNames[I] := AParamValueNames[ipn];
end
else
raise ESLTDBQuerySQLGeneratorError.CreateFmt(ERR_INCOHERENT_PREPARE_ERROR_FMT, [IN_COMPOSITE, FN_INSERT_PREPARE, KeyName, ERR_KEY_MUST_BE_FIELD_ERROR]); // Pseudo-Assert Exception !
end;
InsertPLSQL := Format(PLSQL_INSERT_WITH_COMPOSITE_FMT, [InsertSQL, Returns.CommaText, Params.CommaText, INTERNAL_INSERT_PARAM_NAME_ROW_AFFECTED]);
{$IFDEF DEBUG_SLT_ODAC}FQueryEngine.OutputDebugSQL(InsertPLSQL);{$ENDIF DEBUG_SLT_ODAC}
FQueryEngine.SetSQLText(InsertPLSQL);
finally
Returns.Free();
end;
finally
Params.Free();
end;
end
else
begin
InsertPLSQL := Format(PLSQL_INSERT_NO_KEYS_FMT, [InsertSQL, INTERNAL_INSERT_PARAM_NAME_ROW_AFFECTED]);
{$IFDEF DEBUG_SLT_ODAC}FQueryEngine.OutputDebugSQL(InsertPLSQL);{$ENDIF DEBUG_SLT_ODAC}
FQueryEngine.SetSQLText(InsertPLSQL);
end;
// Renseigne le type de données et la direction des paramètres (y compris les valeurs de retour)
// En Delphi, True c'est $FFFFFFFF, donc -1
// En Oracle, Cela semble gérer correctement le 0 pour False ou 1 pour True dans un NUMBER(1) que l'on considère comme un Booléen
for I := Low(AParamValueNames) to High(AParamValueNames) do
begin
Param := FQueryEngine.FindParam(AParamValueNames[I]);
if Assigned(Param) then
begin
if MatchStr(Param.Name, OutParamNames) then
begin
Param.ParamType := ptInputOutput;
Param.DataType := AParamValueDataTypes[I];
end
else
begin
Param.ParamType := ptInput;
Param.DataType := AParamValueDataTypes[I];
end;
end
else
raise ESLTDBQuerySQLGeneratorError.CreateFmt(ERR_INCOHERENT_PREPARE_ERROR_FMT, [IN_COMPOSITE, FN_INSERT_PREPARE, AParamValueNames[I], ERR_PARAM_NOT_FOUND]); // Pseudo-Assert Exception !
end;
// Renseigne le type de données et la direction du paramètre interne gérant le nombre d'élément inséré compensant la valeur douteuse du RowsAffected
Param := FQueryEngine.FindParam(INTERNAL_INSERT_PARAM_NAME_ROW_AFFECTED);
if Assigned(Param) then
begin
Param.ParamType := ptOutput;
Param.DataType := ftLargeInt;
end
else
raise ESLTDBQuerySQLGeneratorError.CreateFmt(ERR_INCOHERENT_PREPARE_ERROR_FMT, [IN_COMPOSITE, FN_INSERT_PREPARE, INTERNAL_INSERT_PARAM_NAME_ROW_AFFECTED, ERR_PARAM_NOT_FOUND]); // Pseudo-Assert Exception !
// Préparation du SQL INSERT généré
// Prépare la requête avec ses paramètres typés mais sans valeurs !
Result := FQueryEngine.Prepare();
end; |
Partager