02.update.pas 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. Program update;
  2. {*
  3. * PROGRAM: Object oriented API samples.
  4. * MODULE: 02.update.cpp
  5. * DESCRIPTION: Run once prepared statement with parameters
  6. * a few times, committing transaction after each run.
  7. * Learns how to prepare statement, manually define parameters
  8. * for it, execute that statement with different parameters
  9. * and perform non-default error processing.
  10. *
  11. * Example for the following interfaces:
  12. * IAttachment - database attachment
  13. * ITransaction - transaction
  14. * IStatement - SQL statement execution
  15. * IMessageMetadata - describe input and output data format
  16. * IMetadataBuilder - tool to modify/create metadata
  17. * IStatus - return state holder
  18. *
  19. * Note that all updates are rolled back in this version. (see *** later)
  20. *
  21. * Run something like this to build the program :
  22. *
  23. * fpc -Fu./common -Fu/opt/firebird/include/firebird -FUlib -oupdate 02.update.pas
  24. *
  25. * The contents of this file are subject to the Initial
  26. * Developer's Public License Version 1.0 (the "License");
  27. * you may not use this file except in compliance with the
  28. * License. You may obtain a copy of the License at
  29. * https://www.ibphoenix.com/about/firebird/idpl.
  30. *
  31. * Software distributed under the License is distributed AS IS,
  32. * WITHOUT WARRANTY OF ANY KIND, either express or implied.
  33. * See the License for the specific language governing rights
  34. * and limitations under the License.
  35. *
  36. * The Original Code was created by Paul Reeves
  37. * for the Firebird Open Source RDBMS project.
  38. *
  39. * All Rights Reserved.
  40. * Contributor(s): ______________________________________.
  41. *
  42. *}
  43. {$mode Delphi}{$H+}
  44. Uses
  45. SysUtils,
  46. Firebird;
  47. Type
  48. Buffer = String [255];
  49. Var
  50. // master and status are required for all access to the API.
  51. // This is main interface of firebird, and the only one
  52. // for getting which there is special function in our API
  53. master: IMaster;
  54. // Status is used to return error description to user
  55. status: IStatus;
  56. // Provider is needed to start to work with database (or service)
  57. prov: IProvider;
  58. // declare pointers to required interfaces
  59. att: IAttachment;
  60. tra: ITransaction;
  61. // Interface executes prepared SQL statement
  62. stmt: IStatement;
  63. // Interfaces provides access to format of data in messages
  64. meta: IMessageMetadata;
  65. // Interface makes it possible to change format of data or define it yourself
  66. builder: IMetadataBuilder;
  67. Dept_Data: Array[0..4] Of String = ( '622', '100', '116', '900', '0' );
  68. Percent_data: Array[0..4] Of Double = ( 0.05, 1.00, 0.075, 0.10, 0 );
  69. i: Integer;
  70. InputBuffer: Buffer;
  71. len: Integer;
  72. PPercent_inc: PChar;
  73. PDept_no: PChar;
  74. Const
  75. UpdateString = 'UPDATE department SET budget = ? * budget + budget WHERE dept_no = ?';
  76. SQL_DIALECT_V6 = 3;
  77. SQL_DIALECT_CURRENT = SQL_DIALECT_V6;
  78. SQL_TEXT = 452; // CHAR
  79. SQL_DOUBLE = 480; // DOUBLE PRECISION
  80. Procedure PrintError( AMaster: IMaster; AStatus: IStatus );
  81. Var
  82. maxMessage: Integer;
  83. outMessage: PAnsiChar;
  84. Begin
  85. maxMessage := 256;
  86. outMessage := StrAlloc( maxMessage );
  87. AMaster.getUtilInterface.formatStatus( outMessage, maxMessage, AStatus );
  88. writeln( outMessage );
  89. StrDispose( outMessage );
  90. End;
  91. // Get the department and percent parameters for an example to run.
  92. Begin
  93. master := fb_get_master_interface;
  94. status := master.getStatus;
  95. Try
  96. // the main dispatcher is returned by a call to IMaster
  97. // no errors can occur - this function will always succeed
  98. prov := master.getDispatcher;
  99. // We assume that ISC_USER and ISC_PASSWORD env vars are set. Otherwise,
  100. // see code in 01.create for an example of setting the un/pw via the dpb.
  101. att := prov.attachDatabase( status, 'employee', 0, nil );
  102. writeln( 'Attached to database employee.fdb' );
  103. // start transaction
  104. tra := att.startTransaction( status, 0, nil );
  105. // prepare statement
  106. stmt := att.prepare( status, tra, 0, UpdateString, SQL_DIALECT_CURRENT, 0 );
  107. // build metadata
  108. // IMaster creates empty new metadata in builder
  109. builder := master.getMetadataBuilder( status, 2 );
  110. // set required info on fields
  111. builder.setType( status, 0, SQL_DOUBLE + 1 );
  112. builder.setType( status, 1, SQL_TEXT + 1 );
  113. builder.setLength( status, 1, 3 );
  114. // IMetadata should be ready
  115. meta := builder.getMetadata( status );
  116. // no need for builder any more
  117. builder.Release( );
  118. builder := nil;
  119. len := meta.getMessageLength( status );
  120. If ( len > sizeof( InputBuffer ) ) Then
  121. Raise Exception.Create( 'Input message length too big - cannot continue' )
  122. Else
  123. FillChar( InputBuffer, SizeOf( InputBuffer ), 0 );
  124. i := meta.getNullOffset( status, 0 );
  125. InputBuffer[i] := Char( 0 );
  126. i := meta.getNullOffset( status, 1 );
  127. InputBuffer[i] := Char( 0 );
  128. Try
  129. // locations of parameters in input message
  130. PPercent_inc := PChar( @InputBuffer [meta.getOffset( status, 0 )] );
  131. PDept_no := PChar( @InputBuffer [meta.getOffset( status, 1 )] );
  132. For i := 0 To length( Dept_Data ) - 1 Do Begin
  133. If ( Dept_Data [i] = '0' ) Or ( Percent_data [i] = 0 ) Then
  134. break;
  135. StrPCopy( PPercent_inc, Percent_data [i].ToString );
  136. StrPCopy( PDept_no, Dept_Data [i] );
  137. WriteLn( 'Increasing budget for department: ' + PDept_no + ' by ' + PPercent_inc + ' percent.' );
  138. Try
  139. stmt.Execute( status, tra, meta, @InputBuffer, nil, nil );
  140. // Save/Cancel each department's update independently.
  141. // *** Change to commitRetaining() to see changes
  142. // *** tra.commitRetaining(status);
  143. tra.rollbackRetaining( status );
  144. Except
  145. on E: FBException Do Begin
  146. PrintError( master, status );
  147. tra.rollbackRetaining( status );
  148. End;
  149. End;
  150. End;
  151. stmt.Free( status );
  152. stmt := nil;
  153. meta.Release;
  154. meta := nil;
  155. tra.commit( status );
  156. tra := nil;
  157. att.detach( status );
  158. att := nil;
  159. Except
  160. on E: FBException Do Begin
  161. PrintError( master, status );
  162. tra.rollbackRetaining( status );
  163. End;
  164. on E: Exception Do
  165. WriteLn( E.Message );
  166. End;
  167. Finally
  168. If assigned( meta ) Then
  169. meta.Release;
  170. If assigned( builder ) Then
  171. builder.Release;
  172. If assigned( stmt ) Then
  173. stmt.Release;
  174. If assigned( tra ) Then
  175. tra.Release;
  176. If assigned( att ) Then
  177. att.Release;
  178. prov.Release;
  179. status.dispose;
  180. End;
  181. End.