home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / sqlcla.zip / SQLCLASS.DOC < prev    next >
Text File  |  1993-07-15  |  12KB  |  274 lines

  1. (C) Copyright Stephen B. Behman, 1993 -- All rights reserved.
  2.  
  3. $Header: d:/sh/RCS/sqlclass.doc 1.1 93/07/14 10:14:19 Steve Exp $
  4.  
  5. The stuff accompanying this doc and the doc itself are the copyrighted
  6. property of Steve Behman.  You may copy, modify and distribute it without
  7. payment of any royalty but YOU MUST INCLUDE THE COPYRIGHT NOTICE appearing on
  8. the top line of this doc in all code and documentation referring to code
  9. prepared from this and in each .exe or .dll for which the accompanying code
  10. is used.
  11.  
  12. It is not that I want credit, I am a "control freak" and just don't want to
  13. lose all control. Also if you find it particularly useful I wouldn't object
  14. to you making a cash contribution so that I can afford the time to improve it.
  15.  
  16. This C++ Class library encapsulates "Embedded SQL."  It was written in
  17. self defense to avoid the drudgery of EMBEDDED SQL and most of all the
  18. horrors of coding for SQLPREP.
  19.  
  20. There are 8 files accompanying this doc:
  21. 1) SQL.CPP, the implementation of the classes which do the work;
  22. 2) SQL.HPP, a header file for .SPP programs which include the required
  23.    definitions but leave out most of the implementation;
  24. 3) PREPRE.CMD, a REXX command to pre process .Spp files (build .sqc files for
  25.    SQLPREP);
  26. 4) POSTPRE.CMD, which transforms the .I output of the C Set++ compiler
  27.    into a proper .cpp file to compile with ICC (more about this later);
  28. 5) TT.SPP, A small sample program which a) works (on my Database) and b) gives
  29.    you an idea how to use the classes;
  30. 6) DESCRIBE.CMD which describes the columns in a given table in a specified
  31.    database and provides input to;
  32. 7) MKSQL.CMD, which provides some model code for use in building your
  33.    applications using your database and your tables.
  34.  
  35. While this is a "work in progress" it has been tested on a fair number of
  36. database programs.
  37.  
  38. The basic methodology employs two classes: 1) QUERY and 2) CURSOR.  One other
  39. class ( DATABASE ) is used to encapsulate initialization, the COMMIT and the
  40. ROLLBACK commands for the database.
  41.  
  42. In your application execution an instance of DATABASE must be instantiated
  43. BEFORE ANY OTHER DATABASE CALL is made, probably this is best done before
  44. main() in the module containing main.
  45.  
  46. The most interesting classes are: CURSOR and QUERY which encapsulate most
  47. of the SQL work you will do.
  48.  
  49. A typical program fragment would look like:
  50.  
  51. DATABASE db;                  // starts the dbm
  52.  
  53.  
  54. struct Answer                  // to receive "fetched" data
  55.   {                      // may have members not in a query
  56.    long id;                  // or a cursor -- it is shown only to
  57.    char name[31];              // illustrate the flexibility and
  58.    char addr1[41];              // because I almost always have a
  59.    char addr2[41];              // struct for each table.
  60.    short addr1_nv;              // nothing significant about any of
  61.    short addr2_nv;              // the variable names
  62.   };
  63.  
  64. short a;
  65. extern Answer *answer;
  66. long ct;
  67.  
  68. //  "instantiate" a query
  69.  
  70. QUERY get_count( select count( * ) from names into QV( long :ct )
  71.          where DEPT_NO = QV( short :a )
  72.            );
  73. short depnum;
  74.  
  75. void main()
  76.   {
  77. static CURSOR get_recs( select QV( NAME, char :answer.name[30] ),
  78.             QV( ADDR, char :answer.addr[40] :answer.addr_nv ),
  79.             QV( ID, long :id) from names
  80.             where Dept_no = QV( short :num ) );
  81.  
  82. get_count.exec();
  83. Answer *names=new Answer[ct];
  84. get_recs.open();
  85. for( int i=0; i<ct || i<30; i++ )
  86.   {
  87.    rc=get_recs.fetch();
  88.    names[i]=answer;
  89.   }
  90. get_recs.close();
  91. .
  92. .
  93. delete [] names;              // help avoid memory leaks
  94.  
  95. There is no "Fetch" declaration required -- it is deduced from the CURSOR def.
  96.  
  97. As can be seen the "host variables" can be defined virtually any way you
  98. wish; in this case as members of a structure!
  99.  
  100. The only requirements are: 1) that host vars have FIXED (const) ADDRESSES from
  101. the time that the CURSOR or QUERY constructor is called until it is destroyed;
  102. and 2) vars are such that the "&" operator is meaningful for them; 3) When
  103. you instantiate a CURSOR or QUERY the word (CURSOR or QUERY) and the "("
  104. which starts the initializer MUST BE ON THE SAME LINE and on that line only
  105. there may be no vestige of another statement; 4) the line on which the
  106. statement ends must have the statement terminator ';' preceeded by the closing
  107. ')'.
  108.  
  109. Examples:
  110. these two statements are ok:
  111.  
  112. static CURSOR xmp ( ...          );
  113. __________________________
  114. QUERY abc( ...
  115.        ... );
  116.  
  117. the statment below is doubly bad: something not belonging to the statement
  118. preceeds it on the line the statment starts and the statment terminator is not
  119. on the same line as the closing ")".
  120.  
  121. ; static QUERY def(  )
  122. ;
  123.  
  124. To understand these requirements you must know that BEFORE compile time
  125. the TEXT in the CURSOR or QUERY is manipulated and placed in a call to the
  126. REAL constructor having been prefixed with the "&" operator
  127. and whatever the variable address values are at construction time they
  128. will be when the member functions are executed!  For now, the variables
  129. specified are prefixed with "&" before compile time, those addresses are
  130. stored at CONSTRUCTION time and will be used UNCHANGED until DESTRUCTION time.
  131. This requirement excludes non-const indexes or non-const pointers (i.e. var[i]
  132. or varptr->var where i or varptr will change from the time CURSOR() or QUERY()
  133. are called until the last exec, open, or fetch call using that CURSOR or QUERY)
  134. but includes varptr->var where varptr is const over the life of the CURSOR or
  135. QUERY.    The rub is that if you change an index or a pointer the CHANGE will not
  136. be seen.  The little parser in prepre.cmd does little syntax checking and
  137. cannot handle parentheses within a QV or CV -- don't use them unless you revise
  138. prepre (If you do that send me a copy, please.)
  139.  
  140. NOTE: I may do something to eliminate these restrictions -- but not for a while.
  141.  
  142. The syntax is a simple extension (and contraction) of embedded SQL.
  143.  
  144. Variables which appear in the EXEC SQL FETCH :v1, v2, ... into etc.
  145. are each indicated in a "Cursor Variable"
  146.     CV( COLNAME, type :hostvar:nullindic )
  147.  
  148. All other host vars are described in a "Query Variable"
  149.     QV( type :var :nullindic )
  150.  
  151. EXAMPLE:
  152. Name is declared "char name[30];" and USER_NAME is the database column that
  153. "name" is to receive.  USER_NAME was declared "not null" (in the Database), say
  154. also that name_ptr is declared "char **name_ptr=name;" (note: name is a char*)
  155. Then the two declarations below HAVE EXACTLY THE SAME EFFECT no matter what
  156. happens to name_ptr during the life of the CURSOR in which it is used!!!
  157.  
  158.    CV( USER_NAME, char :name[30] )
  159.  
  160.    CV( USER_NAME, char *name )
  161.  
  162. Any change to name_ptr after the instatiation of the CURSOR goes "unseen."
  163.  
  164. In both the QV and CV "quasi macros" the null indicator is required if and
  165. only if it would have been required in the "standard" equivalent statement.
  166. QV's and CV's are NOT DATATYPES nor are they C++ macros!  They exist solely for
  167. my convenience and are processed by my code only.
  168.  
  169. Please note that the SQL part of the statements DO NOT END IN ";" -- only
  170. the normal C++ ";" statement terminator is required (or can be present!)
  171.  
  172. NOTE: Files coded using these classes must have the .SPP extension; .SQC, .C
  173. .I and, finally .CPP and .OBJ files will be built from them -- what a mess.
  174.  
  175. The syntax is fairly "natural" and is, unfortunately somewhat more complicated
  176. than it need be.  The reason for the extra complexity is the authors desire
  177. to avoid writing a C++ parser!
  178.  
  179. If the compiler folks in Toronto would get together with the DB2 folks (also
  180. in Maple Leaf City -- actually, probably in the same building) they could
  181. refine this in some real and substantive way.  Enough of my wishes!!!
  182.  
  183. In order to use this library in addition to the SQL related classes there
  184. are two REXX commands which must be used.  One of them PREPRE.cmd processes
  185. an .SPP file to make a .SQC file.  This file is PREPROCESSED using SQLPREP.
  186. The resultant .C file is "pre"-processed using the ICC -P command and then
  187. more post-processing (of the resultant .i) file is done using the second
  188. rexx command POSTPRE.cmd.  More about this below.
  189.  
  190. In addition to prepre.cmd and postpre.cmd there are two other rexx commands
  191. which are "Helpers."  The first "Describe.cmd" describes the columns in a
  192. table (using sysibm.systables.)  The second "MKSQL.cmd" builds the QV's for
  193. every column in the table and a structure to receive them.  Each QV for a
  194. var which may be null has a null indicator in it and qualifies the host var
  195. name with a (mandatory for mksql) structure member reference.  The name
  196. of a struture instance is a required command line arg to mksql.
  197.  
  198. The structure name can be deleted or modified as you wish and
  199. Correlation names, where needed, can be freely prepended to the column names
  200. (which have syntactic and lexical value only to DBM via SQLPREP.)
  201.  
  202. MKSQL is only a handy adjunct and its use optional.  MKSQL uses DESCRIBE so
  203. to use MKSQL DESCRIBE must also be in the path.
  204.  
  205.  
  206. Using PREPRE.cmd and POSTPRE.cmd
  207.  
  208. The makefile for all of this processing for ES 1.0 or OS/2 EE 1.3 is:
  209.  
  210. DATABASE=Your_database_name
  211.  
  212. .spp.obj
  213.     prepre $*.spp $*.sqc
  214.     sqlprep $*.sqc $(DATABASE) /b /p /l=1
  215.     icc -p    -tp $*.c
  216.     if exist $*.cpp del $*.cpp
  217.     postpre  $*.i  $*.cpp
  218.     icc /c /gt /sm    $*.cpp
  219.  
  220. sql.obj:sql.cpp
  221.     icc -gt -sm /c $*.cpp
  222.  
  223. All the .objs in the project are linked using:
  224.  
  225. proj.exe: a.obj ... sql.hpp sql.obj  # sql.obj contains the implementation of
  226.    link386  @<<              # sql.hpp -- the class definitions
  227.     /CO /NOL /PM:PM +             # /CO is  for debugging
  228.     $(**: =+^
  229.     )
  230.     ,,NUL,
  231.     sql_dyn.lib              # plus any other libraries you may need.
  232.     ;
  233. <<
  234.  
  235. where DATABASE is the name of the database containing the referenced tables.
  236.  
  237. #include statements where the file spec is enclosed in "<" and ">" are not
  238. included until after postpre is run.  This is to keep the other files as small
  239. as possible.  If you want to exclude an include file in the same subdir as the
  240. project until the final ICC execution then enclose it in <..> and either have
  241. your INCLUDE environment variable be something like .;c:\ibmcpp\include;... or
  242. use the fully qualified name within the <> pair.  This will save you time in
  243. running postpre.
  244.  
  245. I have not yet gotten my hands on DB2/2 but I don't think there will be
  246. much work required to fix my stuff for it.  It will certainly relax the
  247. need for the compiler /gt option and /sm is probably not needed now but I
  248. don't have time to experiment.  If there is any interest I will update it for
  249. DB2/2 when I get the thing which should be "Real soon now."  A fair amount of
  250. the fiddling about in the implementation (sql.cpp) is due to the fact that
  251. addresses stored in an sqlda must be 16:16 for ES 1.0 and EE 1.3 -- the DB2/2
  252. implementation should be somewhat cleaner!
  253.  
  254. For distribution of code developed using the above the bind (.bnd) files
  255. associated with  each .SPP module must be distributed so that the application
  256. can be bound to the user's system.
  257.  
  258. FINAL NOTE:  Little of this code is elegant -- "If I had more time this code
  259. would be neater, shorter and more elegant."  Most of the time spent on this
  260. was spent conceptualizing a "decent and useful" way to go at the thing.
  261. This was especially taxing because of the "brain dead" nature of SQLPREP and my
  262. steadfast unwillingness to write a C++ parser.
  263.  
  264. I would appreciate your reporting any usage, bugs ( and their fixes ) and any
  265. suggestions you might have to me via COMPUSERVE PRIVATE MAIL!!! It is nice to
  266. know whether this scratches an itch that the SQL development community has.
  267. If there is no feedback I will assume I missed the mark and that this is
  268. either incomrehensible or useless or both.
  269.  
  270. Please refer to the version and date info in the Header at the top of each file
  271. in which you find a bug.
  272.  
  273. My COMPUSERVE address is:  Steve Behman [76360,3153].
  274.