sqldb.pp 107 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788
  1. {
  2. Copyright (c) 2004-2014 by Joost van der Sluis, FPC contributors
  3. SQL database & dataset
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. unit SQLDB;
  11. {$mode objfpc}
  12. {$H+}
  13. {$M+} // ### remove this!!!
  14. interface
  15. uses SysUtils, Classes, DB, bufdataset, sqlscript, sqltypes;
  16. type
  17. TSchemaType = sqltypes.TSchemaType;
  18. TStatementType = sqltypes.TStatementType;
  19. TDBEventType = sqltypes.TDBEventType;
  20. TDBEventTypes = sqltypes.TDBEventTypes;
  21. TQuoteChars = sqltypes.TQuoteChars;
  22. const
  23. StatementTokens : Array[TStatementType] of string = ('(unknown)', 'select',
  24. 'insert', 'update', 'delete',
  25. 'create', 'get', 'put', 'execute',
  26. 'start','commit','rollback', '?'
  27. );
  28. TSchemaObjectNames: array[TSchemaType] of String = ('???', 'table_name',
  29. '???', 'procedure_name', 'column_name', 'param_name',
  30. 'index_name', 'package_name', 'schema_name','sequence');
  31. SingleQuotes : TQuoteChars = ('''','''');
  32. DoubleQuotes : TQuoteChars = ('"','"');
  33. LogAllEvents = [detCustom, detPrepare, detExecute, detFetch, detCommit, detRollBack];
  34. LogAllEventsExtra = [detCustom, detPrepare, detExecute, detFetch, detCommit, detRollBack, detParamValue,detActualSQL];
  35. // Backwards compatibility alias constants.
  36. stNoSchema = sqltypes.stNoSchema;
  37. stTables = sqltypes.stTables;
  38. stSysTables = sqltypes.stSysTables;
  39. stProcedures = sqltypes.stProcedures;
  40. stColumns = sqltypes.stColumns;
  41. stProcedureParams = sqltypes.stProcedureParams;
  42. stIndexes = sqltypes.stIndexes;
  43. stPackages = sqltypes.stPackages;
  44. stSchemata = sqltypes.stSchemata;
  45. stSequences = sqltypes.stSequences;
  46. stUnknown = sqltypes.stUnknown;
  47. stSelect = sqltypes.stSelect;
  48. stInsert = sqltypes.stInsert;
  49. stUpdate = sqltypes.stUpdate;
  50. stDelete = sqltypes.stDelete;
  51. stDDL = sqltypes.stDDL;
  52. stGetSegment = sqltypes.stGetSegment;
  53. stPutSegment = sqltypes.stPutSegment;
  54. stExecProcedure = sqltypes.stExecProcedure;
  55. stStartTrans = sqltypes.stStartTrans;
  56. stCommit = sqltypes.stCommit;
  57. stRollback = sqltypes.stRollback;
  58. stSelectForUpd = sqltypes.stSelectForUpd;
  59. detCustom = sqltypes.detCustom;
  60. detPrepare = sqltypes.detPrepare;
  61. detExecute = sqltypes.detExecute;
  62. detFetch = sqltypes.detFetch;
  63. detCommit = sqltypes.detCommit;
  64. detRollBack = sqltypes.detRollBack;
  65. detParamValue = sqltypes.detParamValue;
  66. detActualSQL = sqltypes.detActualSQL;
  67. Type
  68. TRowsCount = LargeInt;
  69. TSQLStatementInfo = Record
  70. StatementType : TStatementType;
  71. TableName : String;
  72. Updateable : Boolean;
  73. WhereStartPos ,
  74. WhereStopPos : integer;
  75. end;
  76. TSQLConnection = class;
  77. TSQLTransaction = class;
  78. TCustomSQLQuery = class;
  79. TCustomSQLStatement = Class;
  80. TSQLQuery = class;
  81. TSQLScript = class;
  82. TSQLHandle = Class(TObject)
  83. end;
  84. { TSQLCursor }
  85. TSQLCursor = Class(TSQLHandle)
  86. public
  87. FPrepared : Boolean;
  88. FSelectable : Boolean;
  89. FInitFieldDef : Boolean;
  90. FStatementType : TStatementType;
  91. FSchemaType : TSchemaType;
  92. end;
  93. { ESQLDatabaseError}
  94. ESQLDatabaseError = class(EDatabaseError)
  95. public
  96. ErrorCode: integer;
  97. SQLState : string;
  98. constructor CreateFmt(const Fmt: string; const Args: array of const;
  99. Comp : TComponent; AErrorCode: integer; ASQLState: string); overload;
  100. end;
  101. { TSQLDBFieldDef }
  102. TSQLDBFieldDef = Class(TFieldDef)
  103. private
  104. FData: Pointer;
  105. Public
  106. Property SQLDBData : Pointer Read FData Write FData;
  107. end;
  108. { TSQLDBFieldDefs }
  109. TSQLDBFieldDefs = Class(TFieldDefs)
  110. Protected
  111. Class Function FieldDefClass : TFieldDefClass; override;
  112. end;
  113. { TSQLDBParam }
  114. TSQLDBParam = Class(TParam)
  115. private
  116. FFieldDef: TFieldDef;
  117. FData : Pointer;
  118. Public
  119. Property FieldDef : TFieldDef Read FFieldDef Write FFieldDef;
  120. Property SQLDBData : Pointer Read FData Write FData;
  121. end;
  122. { TSQLDBParams }
  123. TSQLDBParams = Class(TParams)
  124. Protected
  125. Class Function ParamClass : TParamClass; override;
  126. end;
  127. type
  128. { TServerIndexDefs }
  129. TServerIndexDefs = class(TIndexDefs)
  130. Private
  131. public
  132. constructor Create(ADataSet: TDataSet); override;
  133. procedure Update; override;
  134. end;
  135. type
  136. { TSQLConnection }
  137. TDBLogNotifyEvent = Procedure (Sender : TSQLConnection; EventType : TDBEventType; Const Msg : String) of object;
  138. TConnOption = (sqSupportParams, sqSupportEmptyDatabaseName, sqEscapeSlash, sqEscapeRepeat, sqImplicitTransaction, sqLastInsertID, sqSupportReturning);
  139. TConnOptions= set of TConnOption;
  140. TSQLConnectionOption = (scoExplicitConnect, scoApplyUpdatesChecksRowsAffected);
  141. TSQLConnectionOptions = Set of TSQLConnectionOption;
  142. TConnInfoType=(citAll=-1, citServerType, citServerVersion, citServerVersionString, citClientName, citClientVersion);
  143. TSQLConnection = class (TDatabase)
  144. private
  145. FFieldNameQuoteChars : TQuoteChars;
  146. FOptions : TSQLConnectionOptions;
  147. FPassword : string;
  148. FTransaction : TSQLTransaction;
  149. FUserName : string;
  150. FHostName : string;
  151. FCharSet : string;
  152. FCodePage : TSystemCodePage;
  153. FRole : String;
  154. FStatements : TThreadList;
  155. FLogEvents: TDBEventTypes;
  156. FOnLog: TDBLogNotifyEvent;
  157. function GetPort: cardinal;
  158. procedure SetOptions(AValue: TSQLConnectionOptions);
  159. procedure SetPort(const AValue: cardinal);
  160. function AttemptCommit(trans : TSQLHandle) : boolean;
  161. function AttemptRollBack(trans : TSQLHandle) : boolean;
  162. protected
  163. FConnOptions : TConnOptions;
  164. FSQLFormatSettings : TFormatSettings;
  165. // Updating of DB records is moved out of TSQLQuery.
  166. // It is done here, so descendents can override it and implement DB-specific.
  167. // One day, this may be factored out to a TSQLResolver class.
  168. // The following allow construction of update queries. They can be adapted as needed by descendents to fit the DB engine.
  169. procedure AddFieldToUpdateWherePart(var sql_where: string; UpdateMode : TUpdateMode; F: TField); virtual;
  170. function ConstructInsertSQL(Query: TCustomSQLQuery; Var ReturningClause : Boolean): string; virtual;
  171. function ConstructUpdateSQL(Query: TCustomSQLQuery; Var ReturningClause : Boolean): string; virtual;
  172. function ConstructDeleteSQL(Query: TCustomSQLQuery): string; virtual;
  173. function ConstructRefreshSQL(Query: TCustomSQLQuery; UpdateKind : TUpdateKind): string; virtual;
  174. // factory function used to create custom statements
  175. function CreateCustomQuery(aOwner: TComponent): TCustomSQLQuery; virtual;
  176. function InitialiseUpdateStatement(Query: TCustomSQLQuery; var qry: TCustomSQLQuery): TCustomSQLQuery;
  177. procedure ApplyFieldUpdate(C : TSQLCursor; P: TSQLDBParam; F: TField; UseOldValue: Boolean); virtual;
  178. // This is the call that updates a record, it used to be in TSQLQuery.
  179. procedure ApplyRecUpdate(Query : TCustomSQLQuery; UpdateKind : TUpdateKind); virtual;
  180. function RefreshLastInsertID(Query : TCustomSQLQuery; Field : TField): Boolean; virtual;
  181. procedure GetDBInfo(const ASchemaType : TSchemaType; const ASchemaObjectName, AReturnField : string; AList: TStrings);
  182. function GetConnectionCharSet: string; virtual;
  183. procedure SetTransaction(Value : TSQLTransaction); virtual;
  184. procedure DoConnect; override;
  185. procedure DoInternalConnect; override;
  186. procedure DoInternalDisconnect; override;
  187. function GetAsString(Param: TParam): RawByteString;
  188. function GetAsSQLText(Field : TField) : string; overload; virtual;
  189. function GetAsSQLText(Param : TParam) : string; overload; virtual;
  190. function GetHandle : pointer; virtual;
  191. Function LogEvent(EventType : TDBEventType) : Boolean;
  192. Procedure LogParams(Const AParams : TParams); virtual;
  193. Procedure Log(EventType : TDBEventType; Const Msg : String); virtual;
  194. Procedure RegisterStatement(S : TCustomSQLStatement);
  195. Procedure UnRegisterStatement(S : TCustomSQLStatement);
  196. Function AllocateCursorHandle : TSQLCursor; virtual; abstract;
  197. Procedure DeAllocateCursorHandle(var cursor : TSQLCursor); virtual; abstract;
  198. function StrToStatementType(s : string) : TStatementType; virtual;
  199. procedure PrepareStatement(cursor: TSQLCursor;ATransaction : TSQLTransaction;buf : string; AParams : TParams); virtual; abstract;
  200. procedure UnPrepareStatement(cursor : TSQLCursor); virtual; abstract;
  201. procedure Execute(cursor: TSQLCursor;atransaction:tSQLtransaction; AParams : TParams); virtual; abstract;
  202. function RowsAffected(cursor: TSQLCursor): TRowsCount; virtual;
  203. function Fetch(cursor : TSQLCursor) : boolean; virtual; abstract;
  204. procedure AddFieldDefs(cursor: TSQLCursor; FieldDefs : TFieldDefs); virtual; abstract;
  205. function AddFieldDef(AFieldDefs: TFieldDefs; AFieldNo: Longint; const AName: string; ADataType: TFieldType; ASize, APrecision: Integer; AByteSize, ARequired, AReadOnly: Boolean): TFieldDef;
  206. function LoadField(cursor : TSQLCursor; FieldDef : TFieldDef; buffer : pointer; out CreateBlob : boolean) : boolean; virtual; abstract;
  207. procedure LoadBlobIntoBuffer(FieldDef: TFieldDef;ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction : TSQLTransaction); virtual; abstract;
  208. procedure FreeFldBuffers(cursor : TSQLCursor); virtual;
  209. Function AllocateTransactionHandle : TSQLHandle; virtual; abstract;
  210. function GetTransactionHandle(trans : TSQLHandle): pointer; virtual; abstract;
  211. function Commit(trans : TSQLHandle) : boolean; virtual; abstract;
  212. function RollBack(trans : TSQLHandle) : boolean; virtual; abstract;
  213. function StartImplicitTransaction(trans : TSQLHandle; aParams : string) : boolean; virtual;
  214. function StartDBTransaction(trans : TSQLHandle; aParams : string) : boolean; virtual; abstract;
  215. procedure CommitRetaining(trans : TSQLHandle); virtual; abstract;
  216. procedure RollBackRetaining(trans : TSQLHandle); virtual; abstract;
  217. procedure UpdateIndexDefs(IndexDefs : TIndexDefs; TableName : string); virtual;
  218. function GetSchemaInfoSQL(SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string) : string; virtual;
  219. function GetNextValueSQL(const SequenceName: string; IncrementBy: Integer): string; virtual;
  220. Procedure MaybeConnect;
  221. Property Statements : TThreadList Read FStatements;
  222. property Port: cardinal read GetPort write SetPort;
  223. public
  224. constructor Create(AOwner: TComponent); override;
  225. destructor Destroy; override;
  226. procedure StartTransaction; override;
  227. procedure EndTransaction; override;
  228. procedure ExecuteDirect(SQL : String); overload; virtual;
  229. procedure ExecuteDirect(SQL : String; ATransaction : TSQLTransaction); overload; virtual;
  230. // Unified version
  231. function GetObjectNames(ASchemaType: TSchemaType; AList : TSqlObjectIdentifierList): Integer; virtual;
  232. // Older versions.
  233. procedure GetTableNames(List : TStrings; SystemTables : Boolean = false); virtual;
  234. procedure GetProcedureNames(List : TStrings); virtual;
  235. procedure GetFieldNames(const TableName : string; List : TStrings); virtual;
  236. procedure GetSchemaNames(List: TStrings); virtual;
  237. procedure GetSequenceNames(List: TStrings); virtual;
  238. function GetConnectionInfo(InfoType:TConnInfoType): string; virtual;
  239. function GetStatementInfo(const ASQL: string): TSQLStatementInfo; virtual;
  240. procedure CreateDB; virtual;
  241. procedure DropDB; virtual;
  242. function GetNextValue(const SequenceName: string; IncrementBy: integer=1): Int64; virtual;
  243. property ConnOptions: TConnOptions read FConnOptions;
  244. property Handle: Pointer read GetHandle;
  245. property FieldNameQuoteChars: TQuoteChars read FFieldNameQuoteChars write FFieldNameQuoteChars;
  246. published
  247. property Password : string read FPassword write FPassword;
  248. property Transaction : TSQLTransaction read FTransaction write SetTransaction;
  249. property UserName : string read FUserName write FUserName;
  250. property CharSet : string read FCharSet write FCharSet;
  251. property HostName : string Read FHostName Write FHostName;
  252. Property OnLog : TDBLogNotifyEvent Read FOnLog Write FOnLog;
  253. Property LogEvents : TDBEventTypes Read FLogEvents Write FLogEvents Default LogAllEvents;
  254. Property Options : TSQLConnectionOptions Read FOptions Write SetOptions default [];
  255. Property Role : String read FRole write FRole;
  256. property Connected;
  257. property DatabaseName;
  258. property KeepConnection;
  259. property LoginPrompt;
  260. property Params;
  261. property OnLogin;
  262. end;
  263. { TSQLTransaction }
  264. TCommitRollbackAction = (caNone, caCommit, caCommitRetaining, caRollback,
  265. caRollbackRetaining);
  266. TSQLTransactionOption = (stoUseImplicit, stoExplicitStart);
  267. TSQLTransactionOptions = Set of TSQLTransactionOption;
  268. TSQLTransaction = class (TDBTransaction)
  269. private
  270. FOptions : TSQLTransactionOptions;
  271. FTrans : TSQLHandle;
  272. FAction : TCommitRollbackAction;
  273. FParams : TStringList;
  274. function GetSQLConnection: TSQLConnection;
  275. procedure SetOptions(AValue: TSQLTransactionOptions);
  276. procedure SetParams(const AValue: TStringList);
  277. procedure SetSQLConnection(AValue: TSQLConnection);
  278. protected
  279. Procedure MaybeStartTransaction;
  280. Function AllowClose(DS: TDBDataset): Boolean; override;
  281. function GetHandle : Pointer; virtual;
  282. Procedure SetDatabase (Value : TDatabase); override;
  283. Function LogEvent(EventType : TDBEventType) : Boolean;
  284. Procedure Log(EventType : TDBEventType; Const Msg : String); virtual;
  285. public
  286. constructor Create(AOwner : TComponent); override;
  287. destructor Destroy; override;
  288. procedure Commit; override;
  289. procedure CommitRetaining; override;
  290. procedure Rollback; override;
  291. procedure RollbackRetaining; override;
  292. procedure StartTransaction; override;
  293. procedure EndTransaction; override;
  294. property Handle: Pointer read GetHandle;
  295. Property SQLConnection : TSQLConnection Read GetSQLConnection Write SetSQLConnection;
  296. published
  297. property Action : TCommitRollbackAction read FAction write FAction Default caRollBack;
  298. property Database;
  299. property Params : TStringList read FParams write SetParams;
  300. Property Options : TSQLTransactionOptions Read FOptions Write SetOptions default [];
  301. end;
  302. { TCustomSQLStatement }
  303. TCustomSQLStatement = Class(TComponent)
  304. Private
  305. FCursor : TSQLCursor;
  306. FDatabase: TSQLConnection;
  307. FParamCheck: Boolean;
  308. FParams: TParams;
  309. FSQL: TStrings;
  310. FOrigSQL : String;
  311. FServerSQL : String;
  312. FTransaction: TSQLTransaction;
  313. FParseSQL: Boolean;
  314. FDataLink : TDataLink;
  315. FRowsAffected : TRowsCount;
  316. procedure SetDatabase(AValue: TSQLConnection);
  317. procedure SetParams(AValue: TParams);
  318. procedure SetSQL(AValue: TStrings);
  319. procedure SetTransaction(AValue: TSQLTransaction);
  320. Function GetPrepared : Boolean;
  321. Protected
  322. Function CreateDataLink : TDataLink; virtual;
  323. procedure OnChangeSQL(Sender : TObject); virtual;
  324. function GetDataSource: TDataSource; Virtual;
  325. procedure SetDataSource(AValue: TDataSource); virtual;
  326. Procedure CopyParamsFromMaster(CopyBound : Boolean); virtual;
  327. procedure AllocateCursor;
  328. procedure DeAllocateCursor;
  329. Function GetSchemaType : TSchemaType; virtual;
  330. Function GetSchemaObjectName : String; virtual;
  331. Function GetSchemaPattern: String; virtual;
  332. Function IsSelectable : Boolean ; virtual;
  333. procedure GetStatementInfo(var ASQL: String; out Info: TSQLStatementInfo); virtual;
  334. Procedure DoExecute; virtual;
  335. procedure DoPrepare; virtual;
  336. procedure DoUnPrepare; virtual;
  337. Function CreateParams : TSQLDBParams; virtual;
  338. Function LogEvent(EventType : TDBEventType) : Boolean;
  339. Procedure Log(EventType : TDBEventType; Const Msg : String); virtual;
  340. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  341. Property Cursor : TSQLCursor read FCursor;
  342. Property Database : TSQLConnection Read FDatabase Write SetDatabase;
  343. Property Transaction : TSQLTransaction Read FTransaction Write SetTransaction;
  344. Property SQL : TStrings Read FSQL Write SetSQL;
  345. Property Params : TParams Read FParams Write SetParams;
  346. Property DataSource : TDataSource Read GetDataSource Write SetDataSource;
  347. Property ParseSQL : Boolean Read FParseSQL Write FParseSQL;
  348. Property ParamCheck : Boolean Read FParamCheck Write FParamCheck default true;
  349. Public
  350. constructor Create(AOwner : TComponent); override;
  351. destructor Destroy; override;
  352. Procedure Prepare;
  353. Procedure Execute;
  354. Procedure Unprepare;
  355. function ParamByName(Const AParamName : String) : TParam;
  356. function RowsAffected: TRowsCount; virtual;
  357. Property Prepared : boolean read GetPrepared;
  358. end;
  359. TSQLStatement = Class(TCustomSQLStatement)
  360. Published
  361. Property Database;
  362. Property DataSource;
  363. Property ParamCheck;
  364. Property Params;
  365. Property ParseSQL;
  366. Property SQL;
  367. Property Transaction;
  368. end;
  369. { TSQLSequence }
  370. TSQLSequenceApplyEvent = (saeOnNewRecord, saeOnPost);
  371. TSQLSequence = class(TPersistent)
  372. private
  373. FQuery: TCustomSQLQuery;
  374. FFieldName: String;
  375. FSequenceName: String;
  376. FIncrementBy: Integer;
  377. FApplyEvent: TSQLSequenceApplyEvent;
  378. public
  379. constructor Create(AQuery: TCustomSQLQuery);
  380. procedure Assign(Source: TPersistent); override;
  381. procedure Apply;
  382. function GetNextValue: Int64;
  383. published
  384. property FieldName: String read FFieldName write FFieldName;
  385. property SequenceName: String read FSequenceName write FSequenceName;
  386. property IncrementBy: Integer read FIncrementBy write FIncrementBy default 1;
  387. property ApplyEvent: TSQLSequenceApplyEvent read FApplyEvent write FApplyEvent default saeOnNewRecord;
  388. end;
  389. { TCustomSQLQuery }
  390. TSQLQueryOption = (sqoKeepOpenOnCommit, sqoAutoApplyUpdates, sqoAutoCommit, sqoCancelUpdatesOnRefresh, sqoRefreshUsingSelect);
  391. TSQLQueryOptions = Set of TSQLQueryOption;
  392. TCustomSQLQuery = class (TCustomBufDataset)
  393. private
  394. FOptions : TSQLQueryOptions;
  395. FSchemaType : TSchemaType;
  396. FUpdateable : boolean;
  397. FTableName : string;
  398. FStatement : TCustomSQLStatement;
  399. FInsertSQL,
  400. FUpdateSQL,
  401. FDeleteSQL,
  402. FRefreshSQL : TStringList;
  403. FIsEOF : boolean;
  404. FLoadingFieldDefs : boolean;
  405. FUpdateMode : TUpdateMode;
  406. FusePrimaryKeyAsKey : Boolean;
  407. FWhereStartPos : integer;
  408. FWhereStopPos : integer;
  409. FServerFilterText : string;
  410. FServerFiltered : Boolean;
  411. FServerIndexDefs : TServerIndexDefs;
  412. // Used by SetSchemaType
  413. FSchemaObjectName : string;
  414. FSchemaPattern : string;
  415. FInsertQry,
  416. FUpdateQry,
  417. FDeleteQry : TCustomSQLQuery;
  418. FSequence : TSQLSequence;
  419. procedure FreeFldBuffers;
  420. function GetParamCheck: Boolean;
  421. function GetParams: TParams;
  422. function GetParseSQL: Boolean;
  423. function GetServerIndexDefs: TServerIndexDefs;
  424. function GetSQL: TStringList;
  425. function GetSQLConnection: TSQLConnection;
  426. function GetSQLTransaction: TSQLTransaction;
  427. function GetStatementType : TStatementType;
  428. Function NeedLastInsertID: TField;
  429. procedure SetOptions(AValue: TSQLQueryOptions);
  430. procedure SetParamCheck(AValue: Boolean);
  431. procedure SetSQLConnection(AValue: TSQLConnection);
  432. procedure SetSQLTransaction(AValue: TSQLTransaction);
  433. procedure SetInsertSQL(const AValue: TStringList);
  434. procedure SetUpdateSQL(const AValue: TStringList);
  435. procedure SetDeleteSQL(const AValue: TStringList);
  436. procedure SetRefreshSQL(const AValue: TStringList);
  437. procedure SetParams(AValue: TParams);
  438. procedure SetParseSQL(AValue : Boolean);
  439. procedure SetSQL(const AValue: TStringList);
  440. procedure SetUsePrimaryKeyAsKey(AValue : Boolean);
  441. procedure SetUpdateMode(AValue : TUpdateMode);
  442. procedure OnChangeModifySQL(Sender : TObject);
  443. procedure Execute;
  444. procedure ApplyFilter;
  445. Function AddFilter(SQLstr : string) : string;
  446. protected
  447. function CreateSQLStatement(aOwner: TComponent): TCustomSQLStatement; virtual;
  448. Function CreateParams: TSQLDBParams; virtual;
  449. Function RefreshLastInsertID(Field: TField): Boolean; virtual;
  450. Function NeedRefreshRecord (UpdateKind: TUpdateKind): Boolean; virtual;
  451. Function RefreshRecord (UpdateKind: TUpdateKind) : Boolean; virtual;
  452. Procedure ApplyReturningResult(Q : TCustomSQLQuery; UpdateKind : TUpdateKind);
  453. Function Cursor : TSQLCursor;
  454. Function LogEvent(EventType : TDBEventType) : Boolean;
  455. Procedure Log(EventType : TDBEventType; Const Msg : String); virtual;
  456. // abstract & virtual methods of TBufDataset
  457. function Fetch : boolean; override;
  458. function LoadField(FieldDef : TFieldDef; buffer : pointer; out CreateBlob : boolean) : boolean; override;
  459. procedure LoadBlobIntoBuffer(FieldDef: TFieldDef;ABlobBuf: PBufBlobField); override;
  460. procedure ApplyRecUpdate(UpdateKind : TUpdateKind); override;
  461. procedure SetPacketRecords(aValue : integer); override;
  462. // abstract & virtual methods of TDataset
  463. procedure UpdateServerIndexDefs; virtual;
  464. procedure SetDatabase(Value : TDatabase); override;
  465. Procedure SetTransaction(Value : TDBTransaction); override;
  466. procedure InternalAddRecord(Buffer: Pointer; AAppend: Boolean); override;
  467. procedure InternalClose; override;
  468. procedure InternalInitFieldDefs; override;
  469. procedure InternalOpen; override;
  470. Procedure InternalRefresh; override;
  471. function GetCanModify: Boolean; override;
  472. Function IsPrepared : Boolean; virtual;
  473. Procedure SetActive (Value : Boolean); override;
  474. procedure SetServerFiltered(Value: Boolean); virtual;
  475. procedure SetServerFilterText(const Value: string); virtual;
  476. Function GetDataSource : TDataSource; override;
  477. Procedure SetDataSource(AValue : TDataSource);
  478. procedure BeforeRefreshOpenCursor; override;
  479. procedure SetReadOnly(AValue : Boolean); override;
  480. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  481. procedure DoOnNewRecord; override;
  482. procedure DoBeforePost; override;
  483. class function FieldDefsClass : TFieldDefsClass; override;
  484. // IProviderSupport methods
  485. function PSGetUpdateException(E: Exception; Prev: EUpdateError): EUpdateError; override;
  486. function PSGetTableName: string; override;
  487. Property TableName : String Read FTableName Write FTableName; // alternative: procedure DoGetTableName
  488. public
  489. constructor Create(AOwner : TComponent); override;
  490. destructor Destroy; override;
  491. procedure Prepare; virtual;
  492. procedure UnPrepare; virtual;
  493. procedure ExecSQL; virtual;
  494. procedure SetSchemaInfo( ASchemaType : TSchemaType; ASchemaObjectName, ASchemaPattern : string); virtual;
  495. function RowsAffected: TRowsCount; virtual;
  496. function ParamByName(Const AParamName : String) : TParam;
  497. Property Prepared : boolean read IsPrepared;
  498. Property SQLConnection : TSQLConnection Read GetSQLConnection Write SetSQLConnection;
  499. Property SQLTransaction: TSQLTransaction Read GetSQLTransaction Write SetSQLTransaction;
  500. // overriden TBufDataSet methods
  501. Procedure ApplyUpdates(MaxErrors: Integer); override; overload;
  502. // overriden TDataSet methods
  503. Procedure Post; override;
  504. Procedure Delete; override;
  505. protected
  506. // redeclared TDataSet properties
  507. property Active;
  508. property Filter;
  509. property Filtered;
  510. property BeforeOpen;
  511. property AfterOpen;
  512. property BeforeClose;
  513. property AfterClose;
  514. property BeforeInsert;
  515. property AfterInsert;
  516. property BeforeEdit;
  517. property AfterEdit;
  518. property BeforePost;
  519. property AfterPost;
  520. property BeforeCancel;
  521. property AfterCancel;
  522. property BeforeDelete;
  523. property AfterDelete;
  524. property BeforeRefresh;
  525. property AfterRefresh;
  526. property BeforeScroll;
  527. property AfterScroll;
  528. property OnCalcFields;
  529. property OnDeleteError;
  530. property OnEditError;
  531. property OnFilterRecord;
  532. property OnNewRecord;
  533. property OnPostError;
  534. property AutoCalcFields;
  535. // protected
  536. property Database;
  537. property Transaction;
  538. property SchemaType : TSchemaType read FSchemaType default stNoSchema;
  539. property SQL : TStringlist read GetSQL write SetSQL;
  540. property InsertSQL : TStringList read FInsertSQL write SetInsertSQL;
  541. property UpdateSQL : TStringList read FUpdateSQL write SetUpdateSQL;
  542. property DeleteSQL : TStringList read FDeleteSQL write SetDeleteSQL;
  543. property RefreshSQL : TStringList read FRefreshSQL write SetRefreshSQL;
  544. Property Options : TSQLQueryOptions Read FOptions Write SetOptions default [];
  545. property Params : TParams read GetParams Write SetParams;
  546. Property ParamCheck : Boolean Read GetParamCheck Write SetParamCheck default true;
  547. property ParseSQL : Boolean read GetParseSQL write SetParseSQL default true;
  548. property UpdateMode : TUpdateMode read FUpdateMode write SetUpdateMode default upWhereKeyOnly;
  549. property UsePrimaryKeyAsKey : boolean read FUsePrimaryKeyAsKey write SetUsePrimaryKeyAsKey default true;
  550. property StatementType : TStatementType read GetStatementType;
  551. Property DataSource : TDataSource Read GetDataSource Write SetDataSource;
  552. property Sequence: TSQLSequence read FSequence write FSequence;
  553. property ServerFilter: string read FServerFilterText write SetServerFilterText;
  554. property ServerFiltered: Boolean read FServerFiltered write SetServerFiltered default False;
  555. property ServerIndexDefs : TServerIndexDefs read GetServerIndexDefs;
  556. end;
  557. { TSQLQuery }
  558. TSQLQuery = Class(TCustomSQLQuery)
  559. public
  560. property SchemaType;
  561. Property StatementType;
  562. Published
  563. property MaxIndexesCount;
  564. // TDataset stuff
  565. property FieldDefs;
  566. Property Active;
  567. Property AutoCalcFields;
  568. Property Filter;
  569. Property Filtered;
  570. Property AfterCancel;
  571. Property AfterClose;
  572. Property AfterDelete;
  573. Property AfterEdit;
  574. Property AfterInsert;
  575. Property AfterOpen;
  576. Property AfterPost;
  577. Property AfterRefresh;
  578. Property AfterScroll;
  579. Property BeforeCancel;
  580. Property BeforeClose;
  581. Property BeforeDelete;
  582. Property BeforeEdit;
  583. Property BeforeInsert;
  584. Property BeforeOpen;
  585. Property BeforePost;
  586. Property BeforeRefresh;
  587. Property BeforeScroll;
  588. Property OnCalcFields;
  589. Property OnDeleteError;
  590. Property OnEditError;
  591. Property OnFilterRecord;
  592. Property OnNewRecord;
  593. Property OnPostError;
  594. // property SchemaInfo default stNoSchema;
  595. property Database;
  596. property Transaction;
  597. property ReadOnly;
  598. property SQL;
  599. property InsertSQL;
  600. property UpdateSQL;
  601. property DeleteSQL;
  602. property RefreshSQL;
  603. property IndexDefs;
  604. Property Options;
  605. property Params;
  606. Property ParamCheck;
  607. property ParseSQL;
  608. property UpdateMode;
  609. property UsePrimaryKeyAsKey;
  610. Property DataSource;
  611. property Sequence;
  612. property ServerFilter;
  613. property ServerFiltered;
  614. property ServerIndexDefs;
  615. end;
  616. { TSQLScript }
  617. TSQLScript = class (TCustomSQLscript)
  618. private
  619. FOnDirective: TSQLScriptDirectiveEvent;
  620. FQuery : TCustomSQLQuery;
  621. FDatabase : TDatabase;
  622. FTransaction : TDBTransaction;
  623. protected
  624. procedure ExecuteStatement (SQLStatement: TStrings; var StopExecution: Boolean); override;
  625. procedure ExecuteDirective (Directive, Argument: String; var StopExecution: Boolean); override;
  626. procedure ExecuteCommit(CommitRetaining: boolean=true); override;
  627. Procedure SetDatabase (Value : TDatabase); virtual;
  628. Procedure SetTransaction(Value : TDBTransaction); virtual;
  629. Procedure CheckDatabase;
  630. function CreateQuery: TCustomSQLQuery; virtual;
  631. public
  632. constructor Create(AOwner : TComponent); override;
  633. destructor Destroy; override;
  634. procedure Execute; override;
  635. procedure ExecuteScript;
  636. Property Aborted;
  637. Property Line;
  638. published
  639. Property DataBase : TDatabase Read FDatabase Write SetDatabase;
  640. Property Transaction : TDBTransaction Read FTransaction Write SetTransaction;
  641. property OnDirective: TSQLScriptDirectiveEvent read FOnDirective write FOnDirective;
  642. Property AutoCommit;
  643. Property UseDollarString;
  644. Property DollarStrings;
  645. property Directives;
  646. property Defines;
  647. property Script;
  648. property Terminator;
  649. property CommentsinSQL;
  650. property UseSetTerm;
  651. property UseCommit;
  652. property UseDefines;
  653. property OnException;
  654. end;
  655. { TSQLConnector }
  656. TSQLConnector = Class(TSQLConnection)
  657. private
  658. FProxy : TSQLConnection;
  659. FConnectorType: String;
  660. procedure SetConnectorType(const AValue: String);
  661. protected
  662. procedure SetTransaction(Value : TSQLTransaction);override;
  663. procedure DoInternalConnect; override;
  664. procedure DoInternalDisconnect; override;
  665. Procedure CheckProxy;
  666. Procedure CreateProxy; virtual;
  667. Procedure FreeProxy; virtual;
  668. function StrToStatementType(s : string) : TStatementType; override;
  669. function GetAsSQLText(Field : TField) : string; overload; override;
  670. function GetAsSQLText(Param : TParam) : string; overload; override;
  671. function GetHandle : pointer; override;
  672. Function AllocateCursorHandle : TSQLCursor; override;
  673. Procedure DeAllocateCursorHandle(var cursor : TSQLCursor); override;
  674. Function AllocateTransactionHandle : TSQLHandle; override;
  675. procedure PrepareStatement(cursor: TSQLCursor;ATransaction : TSQLTransaction;buf : string; AParams : TParams); override;
  676. procedure Execute(cursor: TSQLCursor;atransaction:tSQLtransaction; AParams : TParams); override;
  677. function RowsAffected(cursor: TSQLCursor): TRowsCount; override;
  678. function Fetch(cursor : TSQLCursor) : boolean; override;
  679. procedure AddFieldDefs(cursor: TSQLCursor; FieldDefs : TfieldDefs); override;
  680. procedure UnPrepareStatement(cursor : TSQLCursor); override;
  681. function LoadField(cursor : TSQLCursor; FieldDef : TFieldDef; buffer : pointer; out CreateBlob : boolean) : boolean; override;
  682. procedure LoadBlobIntoBuffer(FieldDef: TFieldDef;ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction : TSQLTransaction); override;
  683. procedure FreeFldBuffers(cursor : TSQLCursor); override;
  684. function GetNextValueSQL(const SequenceName: string; IncrementBy: Integer): string; override;
  685. function GetTransactionHandle(trans : TSQLHandle): pointer; override;
  686. function Commit(trans : TSQLHandle) : boolean; override;
  687. function RollBack(trans : TSQLHandle) : boolean; override;
  688. function StartDBTransaction(trans : TSQLHandle; aParams : string) : boolean; override;
  689. procedure CommitRetaining(trans : TSQLHandle); override;
  690. procedure RollBackRetaining(trans : TSQLHandle); override;
  691. procedure UpdateIndexDefs(IndexDefs : TIndexDefs; TableName : string); override;
  692. function GetSchemaInfoSQL(SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string) : string; override;
  693. Property Proxy : TSQLConnection Read FProxy;
  694. Published
  695. Property ConnectorType : String Read FConnectorType Write SetConnectorType;
  696. end;
  697. TSQLConnectionClass = Class of TSQLConnection;
  698. { TConnectionDef }
  699. TLibraryLoadFunction = Function (Const S : AnsiString) : Integer;
  700. TLibraryUnLoadFunction = Procedure;
  701. TConnectionDef = Class(TPersistent)
  702. Class Function TypeName : String; virtual;
  703. Class Function ConnectionClass : TSQLConnectionClass; virtual;
  704. Class Function Description : String; virtual;
  705. Class Function DefaultLibraryName : String; virtual;
  706. Class Function LoadFunction : TLibraryLoadFunction; virtual;
  707. Class Function UnLoadFunction : TLibraryUnLoadFunction; virtual;
  708. Class Function LoadedLibraryName : string; virtual;
  709. Procedure ApplyParams(Params : TStrings; AConnection : TSQLConnection); virtual;
  710. end;
  711. TConnectionDefClass = class of TConnectionDef;
  712. Var
  713. GlobalDBLogHook : TDBLogNotifyEvent;
  714. Procedure RegisterConnection(Def : TConnectionDefClass);
  715. Procedure UnRegisterConnection(Def : TConnectionDefClass);
  716. Procedure UnRegisterConnection(ConnectionName : String);
  717. Function GetConnectionDef(ConnectorName : String) : TConnectionDef;
  718. Procedure GetConnectionList(List : TSTrings);
  719. const DefaultSQLFormatSettings : TFormatSettings = (
  720. CurrencyFormat: 1;
  721. NegCurrFormat: 5;
  722. ThousandSeparator: #0;
  723. DecimalSeparator: '.';
  724. CurrencyDecimals: 2;
  725. DateSeparator: '-';
  726. TimeSeparator: ':';
  727. ListSeparator: ' ';
  728. CurrencyString: '$';
  729. ShortDateFormat: 'yyyy-mm-dd';
  730. LongDateFormat: '';
  731. TimeAMString: '';
  732. TimePMString: '';
  733. ShortTimeFormat: 'hh:nn:ss';
  734. LongTimeFormat: 'hh:nn:ss.zzz';
  735. ShortMonthNames: ('','','','','','','','','','','','');
  736. LongMonthNames: ('','','','','','','','','','','','');
  737. ShortDayNames: ('','','','','','','');
  738. LongDayNames: ('','','','','','','');
  739. TwoDigitYearCenturyWindow: 50;
  740. );
  741. implementation
  742. uses dbconst, strutils;
  743. Const
  744. // Flags to check which fields must be refreshed.
  745. RefreshFlags : Array [ukModify..ukInsert] of TProviderFlag = (pfRefreshOnUpdate,pfRefreshOnInsert);
  746. function TimeIntervalToString(Time: TDateTime): string;
  747. var
  748. millisecond: word;
  749. second : word;
  750. minute : word;
  751. hour : word;
  752. begin
  753. DecodeTime(Time,hour,minute,second,millisecond);
  754. hour := hour + trunc(Time)*24;
  755. Result := Format('%.2d:%.2d:%.2d.%.3d',[hour,minute,second,millisecond]);
  756. end;
  757. { TSQLDBFieldDefs }
  758. class function TSQLDBFieldDefs.FieldDefClass: TFieldDefClass;
  759. begin
  760. Result:=TSQLDBFieldDef;
  761. end;
  762. { TSQLDBParams }
  763. class function TSQLDBParams.ParamClass: TParamClass;
  764. begin
  765. Result:=TSQLDBParam;
  766. end;
  767. { ESQLDatabaseError }
  768. constructor ESQLDatabaseError.CreateFmt(const Fmt: string; const Args: array of const;
  769. Comp: TComponent; AErrorCode: integer; ASQLState: string);
  770. const CompNameFmt='%s : %s';
  771. var Msg: string;
  772. begin
  773. if not assigned(Comp) then
  774. Msg := Fmt
  775. else if Comp.Name = '' then
  776. Msg := Format(CompNameFmt, [Comp.ClassName,Fmt])
  777. else
  778. Msg := Format(CompNameFmt, [Comp.Name,Fmt]);
  779. if Length(Args) = 0 then
  780. inherited Create(Msg)
  781. else
  782. inherited CreateFmt(Msg, Args);
  783. ErrorCode := AErrorCode;
  784. SQLState := ASQLState;
  785. end;
  786. { TCustomSQLStatement }
  787. procedure TCustomSQLStatement.OnChangeSQL(Sender: TObject);
  788. var
  789. ConnOptions : TConnOptions;
  790. NewParams: TSQLDBParams;
  791. begin
  792. UnPrepare;
  793. if not ParamCheck then
  794. exit;
  795. if assigned(DataBase) then
  796. ConnOptions:=DataBase.ConnOptions
  797. else
  798. ConnOptions := [sqEscapeRepeat,sqEscapeSlash];
  799. NewParams := CreateParams;
  800. try
  801. NewParams.ParseSQL(FSQL.Text, True, sqEscapeSlash in ConnOptions, sqEscapeRepeat in ConnOptions, psInterbase);
  802. NewParams.AssignValues(FParams);
  803. FParams.Assign(NewParams);
  804. finally
  805. NewParams.Free;
  806. end;
  807. end;
  808. procedure TCustomSQLStatement.SetDatabase(AValue: TSQLConnection);
  809. begin
  810. if FDatabase=AValue then Exit;
  811. UnPrepare;
  812. If Assigned(FDatabase) then
  813. begin
  814. FDatabase.UnregisterStatement(Self);
  815. FDatabase.RemoveFreeNotification(Self);
  816. end;
  817. FDatabase:=AValue;
  818. If Assigned(FDatabase) then
  819. begin
  820. FDatabase.FreeNotification(Self);
  821. FDatabase.RegisterStatement(Self);
  822. if Assigned(Database.Transaction) and (not Assigned(Transaction) or (Transaction.DataBase <> Database)) then
  823. Transaction := Database.Transaction;
  824. OnChangeSQL(Self);
  825. end;
  826. end;
  827. procedure TCustomSQLStatement.SetTransaction(AValue: TSQLTransaction);
  828. begin
  829. if FTransaction=AValue then Exit;
  830. UnPrepare;
  831. if Assigned(FTransaction) then
  832. FTransaction.RemoveFreeNotification(Self);
  833. FTransaction:=AValue;
  834. if Assigned(FTransaction) then
  835. begin
  836. FTransaction.FreeNotification(Self);
  837. if Assigned(Transaction.DataBase) and (Database <> Transaction.DataBase) then
  838. Database := Transaction.DataBase as TSQLConnection;
  839. end;
  840. end;
  841. procedure TCustomSQLStatement.SetDataSource(AValue: TDataSource);
  842. begin
  843. if GetDataSource=AValue then Exit;
  844. if (FDataLink=Nil) then
  845. FDataLink:=CreateDataLink;
  846. FDataLink.DataSource:=AValue;
  847. end;
  848. Procedure TCustomSQLStatement.CopyParamsFromMaster(CopyBound: Boolean);
  849. begin
  850. if Assigned(DataSource) and Assigned(DataSource.Dataset) then
  851. FParams.CopyParamValuesFromDataset(DataSource.Dataset,CopyBound);
  852. end;
  853. procedure TCustomSQLStatement.SetParams(AValue: TParams);
  854. begin
  855. if FParams=AValue then Exit;
  856. FParams.Assign(AValue);
  857. end;
  858. procedure TCustomSQLStatement.SetSQL(AValue: TStrings);
  859. begin
  860. if FSQL=AValue then Exit;
  861. FSQL.Assign(AValue);
  862. end;
  863. Procedure TCustomSQLStatement.DoExecute;
  864. begin
  865. FRowsAffected:=-1;
  866. If (FParams.Count>0) and Assigned(DataSource) then
  867. CopyParamsFromMaster(False);
  868. If LogEvent(detExecute) then
  869. Log(detExecute,FServerSQL);
  870. Database.Execute(FCursor,Transaction, FParams);
  871. end;
  872. Function TCustomSQLStatement.GetPrepared: Boolean;
  873. begin
  874. Result := Assigned(FCursor) and FCursor.FPrepared;
  875. end;
  876. Function TCustomSQLStatement.CreateDataLink: TDataLink;
  877. begin
  878. Result:=TDataLink.Create;
  879. end;
  880. Function TCustomSQLStatement.CreateParams: TSQLDBParams;
  881. begin
  882. Result:=TSQLDBParams.Create(Nil);
  883. end;
  884. Function TCustomSQLStatement.LogEvent(EventType: TDBEventType): Boolean;
  885. begin
  886. Result:=Assigned(Database) and Database.LogEvent(EventType);
  887. end;
  888. Procedure TCustomSQLStatement.Log(EventType: TDBEventType; Const Msg: String);
  889. Var
  890. M : String;
  891. begin
  892. If LogEvent(EventType) then
  893. begin
  894. If (Name<>'') then
  895. M:=Name
  896. else
  897. M:=ClassName;
  898. Database.Log(EventType,M+' : '+Msg);
  899. end;
  900. end;
  901. procedure TCustomSQLStatement.Notification(AComponent: TComponent;
  902. Operation: TOperation);
  903. begin
  904. inherited Notification(AComponent, Operation);
  905. if (operation=opRemove) then
  906. If (AComponent=FTransaction) then
  907. FTransaction:=Nil
  908. else if (AComponent=FDatabase) then
  909. begin
  910. UnPrepare;
  911. FDatabase:=Nil;
  912. end;
  913. end;
  914. constructor TCustomSQLStatement.Create(AOwner: TComponent);
  915. begin
  916. inherited Create(AOwner);
  917. FSQL:=TStringList.Create;
  918. TStringList(FSQL).OnChange:=@OnChangeSQL;
  919. FParams:=CreateParams;
  920. FParamCheck:=True;
  921. FParseSQL:=True;
  922. FRowsAffected:=-1;
  923. end;
  924. destructor TCustomSQLStatement.Destroy;
  925. begin
  926. UnPrepare;
  927. Transaction:=Nil;
  928. Database:=Nil;
  929. DataSource:=Nil;
  930. FreeAndNil(FDataLink);
  931. FreeAndNil(FParams);
  932. FreeAndNil(FSQL);
  933. inherited Destroy;
  934. end;
  935. Function TCustomSQLStatement.GetSchemaType: TSchemaType;
  936. begin
  937. Result:=stNoSchema
  938. end;
  939. Function TCustomSQLStatement.GetSchemaObjectName: String;
  940. begin
  941. Result:='';
  942. end;
  943. Function TCustomSQLStatement.GetSchemaPattern: String;
  944. begin
  945. Result:='';
  946. end;
  947. Function TCustomSQLStatement.IsSelectable: Boolean;
  948. begin
  949. Result:=False;
  950. end;
  951. procedure TCustomSQLStatement.GetStatementInfo(var ASQL: String; out Info: TSQLStatementInfo);
  952. begin
  953. Info:=Database.GetStatementInfo(ASQL);
  954. end;
  955. procedure TCustomSQLStatement.AllocateCursor;
  956. begin
  957. if not assigned(FCursor) then
  958. // Do this as late as possible.
  959. FCursor:=Database.AllocateCursorHandle;
  960. end;
  961. procedure TCustomSQLStatement.DeAllocateCursor;
  962. begin
  963. if Assigned(FCursor) and Assigned(Database) then
  964. DataBase.DeAllocateCursorHandle(FCursor);
  965. end;
  966. procedure TCustomSQLStatement.DoPrepare;
  967. var
  968. StmInfo: TSQLStatementInfo;
  969. begin
  970. if GetSchemaType=stNoSchema then
  971. FOrigSQL := TrimRight(FSQL.Text)
  972. else
  973. FOrigSQL := Database.GetSchemaInfoSQL(GetSchemaType, GetSchemaObjectName, GetSchemaPattern);
  974. if (FOrigSQL='') then
  975. DatabaseError(SErrNoStatement);
  976. FServerSQL:=FOrigSQL;
  977. GetStatementInfo(FServerSQL,StmInfo);
  978. AllocateCursor;
  979. FCursor.FSelectable:=True; // let PrepareStatement and/or Execute alter it
  980. FCursor.FStatementType:=StmInfo.StatementType;
  981. FCursor.FSchemaType:=GetSchemaType;
  982. If LogEvent(detPrepare) then
  983. Log(detPrepare,FServerSQL);
  984. Database.PrepareStatement(FCursor,Transaction,FServerSQL,FParams);
  985. end;
  986. Procedure TCustomSQLStatement.Prepare;
  987. begin
  988. if Prepared then exit;
  989. if not assigned(Database) then
  990. DatabaseError(SErrDatabasenAssigned);
  991. if not assigned(Transaction) then
  992. DatabaseError(SErrTransactionnSet);
  993. Database.MaybeConnect;
  994. if not Transaction.Active then
  995. Transaction.MaybeStartTransaction;
  996. try
  997. DoPrepare;
  998. except
  999. DeAllocateCursor;
  1000. Raise;
  1001. end;
  1002. end;
  1003. Procedure TCustomSQLStatement.Execute;
  1004. begin
  1005. Prepare;
  1006. DoExecute;
  1007. end;
  1008. procedure TCustomSQLStatement.DoUnPrepare;
  1009. begin
  1010. If Assigned(FCursor) then
  1011. If Assigned(Database) then
  1012. begin
  1013. DataBase.UnPrepareStatement(FCursor);
  1014. DeAllocateCursor;
  1015. end
  1016. else // this should never happen. It means a cursor handle leaks in the DB itself.
  1017. FreeAndNil(FCursor);
  1018. end;
  1019. function TCustomSQLStatement.GetDataSource: TDataSource;
  1020. begin
  1021. if Assigned(FDataLink) then
  1022. Result:=FDataLink.DataSource
  1023. else
  1024. Result:=Nil;
  1025. end;
  1026. Procedure TCustomSQLStatement.Unprepare;
  1027. begin
  1028. // Some SQLConnections does not support statement [un]preparation, but they have allocated local cursor(s)
  1029. // so let them do cleanup f.e. cancel pending queries and/or free resultset
  1030. // and also do UnRegisterStatement!
  1031. if assigned(FCursor) then
  1032. DoUnprepare;
  1033. end;
  1034. function TCustomSQLStatement.ParamByName(Const AParamName: String): TParam;
  1035. begin
  1036. Result:=FParams.ParamByName(AParamName);
  1037. end;
  1038. function TCustomSQLStatement.RowsAffected: TRowsCount;
  1039. begin
  1040. if FRowsAffected=-1 then
  1041. begin
  1042. if Assigned(Database) then
  1043. FRowsAffected:=Database.RowsAffected(FCursor);
  1044. end;
  1045. Result:=FRowsAffected;
  1046. end;
  1047. { TSQLConnection }
  1048. constructor TSQLConnection.Create(AOwner: TComponent);
  1049. begin
  1050. inherited Create(AOwner);
  1051. FSQLFormatSettings:=DefaultSQLFormatSettings;
  1052. FFieldNameQuoteChars:=DoubleQuotes;
  1053. FLogEvents:=LogAllEvents; //match Property LogEvents...Default LogAllEvents
  1054. FStatements:=TThreadList.Create;
  1055. FStatements.Duplicates:=dupIgnore;
  1056. end;
  1057. destructor TSQLConnection.Destroy;
  1058. begin
  1059. Connected:=False; // needed because we want to de-allocate statements
  1060. FreeAndNil(FStatements);
  1061. inherited Destroy;
  1062. end;
  1063. function TSQLConnection.StrToStatementType(s : string) : TStatementType;
  1064. var T : TStatementType;
  1065. begin
  1066. S:=Lowercase(s);
  1067. for T:=stSelect to stRollback do
  1068. if (S=StatementTokens[T]) then
  1069. Exit(T);
  1070. Result:=stUnknown;
  1071. end;
  1072. procedure TSQLConnection.SetTransaction(Value : TSQLTransaction);
  1073. begin
  1074. if FTransaction<>value then
  1075. begin
  1076. if Assigned(FTransaction) and FTransaction.Active then
  1077. DatabaseError(SErrAssTransaction);
  1078. if Assigned(Value) then
  1079. Value.Database := Self;
  1080. FTransaction := Value;
  1081. If Assigned(FTransaction) and (FTransaction.Database=Nil) then
  1082. FTransaction.Database:=Self;
  1083. end;
  1084. end;
  1085. procedure TSQLConnection.UpdateIndexDefs(IndexDefs : TIndexDefs; TableName : string);
  1086. begin
  1087. // Empty abstract
  1088. end;
  1089. procedure TSQLConnection.DoConnect;
  1090. var ConnectionCharSet: string;
  1091. begin
  1092. inherited;
  1093. // map connection CharSet to corresponding local CodePage
  1094. // do not set FCodePage to CP_ACP if FCodePage = DefaultSystemCodePage
  1095. // aliases listed here are commonly used, but not recognized by CodePageNameToCodePage()
  1096. ConnectionCharSet := LowerCase(GetConnectionCharSet);
  1097. case ConnectionCharSet of
  1098. 'utf8','utf-8','utf8mb4':
  1099. FCodePage := CP_UTF8;
  1100. 'win1250','cp1250':
  1101. FCodePage := 1250;
  1102. 'win1251','cp1251':
  1103. FCodePage := 1251;
  1104. 'win1252','cp1252','latin1','iso8859_1':
  1105. FCodePage := 1252;
  1106. else
  1107. begin
  1108. FCodePage := CodePageNameToCodePage(ConnectionCharSet);
  1109. if FCodePage = CP_NONE then
  1110. FCodePage := CP_ACP;
  1111. end;
  1112. end;
  1113. end;
  1114. procedure TSQLConnection.DoInternalConnect;
  1115. begin
  1116. if (DatabaseName = '') and not(sqSupportEmptyDatabaseName in FConnOptions) then
  1117. DatabaseError(SErrNoDatabaseName,Self);
  1118. end;
  1119. procedure TSQLConnection.DoInternalDisconnect;
  1120. Var
  1121. I : integer;
  1122. L : TList;
  1123. begin
  1124. L:=FStatements.LockList;
  1125. try
  1126. For I:=0 to L.Count-1 do
  1127. TCustomSQLStatement(L[i]).Unprepare;
  1128. L.Clear;
  1129. finally
  1130. FStatements.UnlockList;
  1131. end;
  1132. end;
  1133. procedure TSQLConnection.StartTransaction;
  1134. begin
  1135. if not assigned(Transaction) then
  1136. DatabaseError(SErrConnTransactionnSet)
  1137. else
  1138. Transaction.StartTransaction;
  1139. end;
  1140. procedure TSQLConnection.EndTransaction;
  1141. begin
  1142. if not assigned(Transaction) then
  1143. DatabaseError(SErrConnTransactionnSet)
  1144. else
  1145. Transaction.EndTransaction;
  1146. end;
  1147. procedure TSQLConnection.ExecuteDirect(SQL: String);
  1148. begin
  1149. ExecuteDirect(SQL,FTransaction);
  1150. end;
  1151. procedure TSQLConnection.ExecuteDirect(SQL: String;
  1152. ATransaction: TSQLTransaction);
  1153. var Cursor : TSQLCursor;
  1154. begin
  1155. if not assigned(ATransaction) then
  1156. DatabaseError(SErrTransactionnSet);
  1157. if not Connected then Open;
  1158. if not ATransaction.Active then
  1159. ATransaction.MaybeStartTransaction;
  1160. SQL := TrimRight(SQL);
  1161. if SQL = '' then
  1162. DatabaseError(SErrNoStatement);
  1163. try
  1164. Cursor := AllocateCursorHandle;
  1165. Cursor.FStatementType := stUnknown;
  1166. If LogEvent(detPrepare) then
  1167. Log(detPrepare,SQL);
  1168. PrepareStatement(Cursor,ATransaction,SQL,Nil);
  1169. try
  1170. If LogEvent(detExecute) then
  1171. Log(detExecute,SQL);
  1172. Execute(Cursor,ATransaction, Nil);
  1173. finally
  1174. UnPrepareStatement(Cursor);
  1175. end;
  1176. finally;
  1177. DeAllocateCursorHandle(Cursor);
  1178. end;
  1179. end;
  1180. function TSQLConnection.GetPort: cardinal;
  1181. begin
  1182. result := StrToIntDef(Params.Values['Port'],0);
  1183. end;
  1184. procedure TSQLConnection.SetOptions(AValue: TSQLConnectionOptions);
  1185. begin
  1186. if FOptions=AValue then Exit;
  1187. FOptions:=AValue;
  1188. end;
  1189. procedure TSQLConnection.SetPort(const AValue: cardinal);
  1190. begin
  1191. if AValue<>0 then
  1192. Params.Values['Port']:=IntToStr(AValue)
  1193. else with params do if IndexOfName('Port') > -1 then
  1194. Delete(IndexOfName('Port'));
  1195. end;
  1196. function TSQLConnection.AttemptCommit(trans: TSQLHandle): boolean;
  1197. begin
  1198. try
  1199. Result:=Commit(trans);
  1200. except
  1201. if ForcedClose then
  1202. Result:=True
  1203. else
  1204. Raise;
  1205. end;
  1206. end;
  1207. function TSQLConnection.AttemptRollBack(trans: TSQLHandle): boolean;
  1208. begin
  1209. try
  1210. Result:=Rollback(trans);
  1211. except
  1212. if ForcedClose then
  1213. Result:=True
  1214. else
  1215. Raise;
  1216. end;
  1217. end;
  1218. procedure TSQLConnection.GetDBInfo(const ASchemaType : TSchemaType; const ASchemaObjectName, AReturnField : string; AList: TStrings);
  1219. var qry : TCustomSQLQuery;
  1220. begin
  1221. if not assigned(Transaction) then
  1222. DatabaseError(SErrConnTransactionnSet);
  1223. qry := TCustomSQLQuery.Create(nil);
  1224. try
  1225. qry.transaction := Transaction;
  1226. qry.database := Self;
  1227. with qry do
  1228. begin
  1229. ParseSQL := False;
  1230. SetSchemaInfo(ASchemaType,ASchemaObjectName,'');
  1231. open;
  1232. AList.Clear;
  1233. while not eof do
  1234. begin
  1235. AList.Append(trim(fieldbyname(AReturnField).asstring));
  1236. Next;
  1237. end;
  1238. end;
  1239. finally
  1240. qry.free;
  1241. end;
  1242. end;
  1243. function TSQLConnection.GetConnectionCharSet: string;
  1244. begin
  1245. // default implementation returns user supplied FCharSet
  1246. // (can be overriden by descendants, which are able retrieve current connection charset using client API)
  1247. Result := LowerCase(FCharSet);
  1248. end;
  1249. function TSQLConnection.RowsAffected(cursor: TSQLCursor): TRowsCount;
  1250. begin
  1251. Result := -1;
  1252. end;
  1253. function TSQLConnection.AddFieldDef(AFieldDefs: TFieldDefs; AFieldNo: Longint;
  1254. const AName: string; ADataType: TFieldType; ASize, APrecision: Integer;
  1255. AByteSize, ARequired, AReadOnly: Boolean): TFieldDef;
  1256. var
  1257. ACodePage: TSystemCodePage;
  1258. begin
  1259. // helper function used by descendants
  1260. if ADataType in [ftString, ftFixedChar, ftMemo] then
  1261. begin
  1262. ACodePage := FCodePage;
  1263. // if ASize of character data is passed as "byte length",
  1264. // translate it to "character length" as expected by TFieldDef
  1265. if AByteSize and (ACodePage = CP_UTF8) then
  1266. ASize := ASize div 4;
  1267. end
  1268. else
  1269. ACodePage := 0;
  1270. Result := AFieldDefs.Add(AName, ADataType, ASize, APrecision, ARequired, AReadOnly, AFieldNo, ACodePage);
  1271. end;
  1272. procedure TSQLConnection.GetTableNames(List: TStrings; SystemTables: Boolean);
  1273. begin
  1274. if not SystemTables then
  1275. GetDBInfo(stTables,'','table_name',List)
  1276. else
  1277. GetDBInfo(stSysTables,'','table_name',List);
  1278. end;
  1279. procedure TSQLConnection.GetProcedureNames(List: TStrings);
  1280. begin
  1281. GetDBInfo(stProcedures,'','procedure_name',List);
  1282. end;
  1283. procedure TSQLConnection.GetFieldNames(const TableName: string; List: TStrings);
  1284. begin
  1285. GetDBInfo(stColumns,TableName,'column_name',List);
  1286. end;
  1287. procedure TSQLConnection.GetSchemaNames(List: TStrings);
  1288. begin
  1289. GetDBInfo(stSchemata,'','SCHEMA_NAME',List);
  1290. end;
  1291. procedure TSQLConnection.GetSequenceNames(List: TStrings);
  1292. begin
  1293. GetDBInfo(stSequences,'','SEQUENCE_NAME',List);
  1294. end;
  1295. {
  1296. See if we can integrate/merge this with GetDBInfo. They are virtually identical
  1297. }
  1298. Function TSQLConnection.GetObjectNames(ASchemaType: TSchemaType; AList : TSqlObjectIdentifierList) : Integer;
  1299. var
  1300. qry : TCustomSQLQuery;
  1301. vSchemaName, vObjectName: String;
  1302. f: TField;
  1303. begin
  1304. Result:=0;
  1305. if not assigned(Transaction) then
  1306. DatabaseError(SErrConnTransactionnSet);
  1307. qry := TCustomSQLQuery.Create(nil);
  1308. try
  1309. qry.transaction := Transaction;
  1310. qry.database := Self;
  1311. with qry do
  1312. begin
  1313. ParseSQL := False;
  1314. SetSchemaInfo(ASchemaType,TSchemaObjectNames[ASchemaType],'');
  1315. open;
  1316. f:=FindField(TSchemaObjectNames[stSchemata]);
  1317. while not eof do
  1318. begin
  1319. vSchemaName:='';
  1320. if Assigned(f) then
  1321. vSchemaName:=f.AsString;
  1322. vObjectName:=FieldByName(FSchemaObjectName).AsString;
  1323. AList.AddIdentifier(vObjectName, vSchemaName);
  1324. Next;
  1325. Inc(Result);
  1326. end;
  1327. end;
  1328. finally
  1329. qry.free;
  1330. end;
  1331. end;
  1332. function TSQLConnection.GetConnectionInfo(InfoType: TConnInfoType): string;
  1333. var i: TConnInfoType;
  1334. begin
  1335. Result:='';
  1336. if InfoType = citAll then
  1337. for i:=citServerType to citClientVersion do
  1338. begin
  1339. if Result<>'' then Result:=Result+',';
  1340. Result:=Result+'"'+GetConnectionInfo(i)+'"';
  1341. end;
  1342. end;
  1343. function TSQLConnection.GetStatementInfo(const ASQL: string): TSQLStatementInfo;
  1344. type
  1345. TParsePart = (ppStart,ppWith,ppSelect,ppTableName,ppFrom,ppWhere,ppGroup,ppOrder,ppBogus);
  1346. TPhraseSeparator = (sepNone, sepWhiteSpace, sepComma, sepComment, sepParentheses, sepDoubleQuote, sepEnd);
  1347. TKeyword = (kwWITH, kwSELECT, kwINSERT, kwUPDATE, kwDELETE, kwFROM, kwJOIN, kwWHERE, kwGROUP, kwORDER, kwUNION, kwROWS, kwLIMIT, kwUnknown);
  1348. const
  1349. KeywordNames: array[TKeyword] of string =
  1350. ('WITH', 'SELECT', 'INSERT', 'UPDATE', 'DELETE', 'FROM', 'JOIN', 'WHERE', 'GROUP', 'ORDER', 'UNION', 'ROWS', 'LIMIT', '');
  1351. var
  1352. PSQL, CurrentP, SavedP,
  1353. PhraseP, PStatementPart : pchar;
  1354. S : string;
  1355. ParsePart : TParsePart;
  1356. BracketCount : Integer;
  1357. Separator : TPhraseSeparator;
  1358. Keyword, K : TKeyword;
  1359. begin
  1360. PSQL:=PChar(ASQL);
  1361. ParsePart := ppStart;
  1362. CurrentP := PSQL-1;
  1363. PhraseP := PSQL;
  1364. Result.TableName := '';
  1365. Result.Updateable := False;
  1366. Result.WhereStartPos := 0;
  1367. Result.WhereStopPos := 0;
  1368. repeat
  1369. inc(CurrentP);
  1370. SavedP := CurrentP;
  1371. case CurrentP^ of
  1372. ' ', #9..#13:
  1373. Separator := sepWhiteSpace;
  1374. ',':
  1375. Separator := sepComma;
  1376. #0, ';':
  1377. Separator := sepEnd;
  1378. '(':
  1379. begin
  1380. Separator := sepParentheses;
  1381. // skip everything between brackets, since it could be a sub-select, and
  1382. // further nothing between brackets could be interesting for the parser.
  1383. BracketCount := 1;
  1384. repeat
  1385. inc(CurrentP);
  1386. if CurrentP^ = '(' then inc(BracketCount)
  1387. else if CurrentP^ = ')' then dec(BracketCount);
  1388. until (CurrentP^ = #0) or (BracketCount = 0);
  1389. if CurrentP^ <> #0 then inc(CurrentP);
  1390. end;
  1391. '"','`':
  1392. if SkipComments(CurrentP, sqEscapeSlash in ConnOptions, sqEscapeRepeat in ConnOptions) then
  1393. Separator := sepDoubleQuote;
  1394. else
  1395. if SkipComments(CurrentP, sqEscapeSlash in ConnOptions, sqEscapeRepeat in ConnOptions) then
  1396. Separator := sepComment
  1397. else
  1398. Separator := sepNone;
  1399. end;
  1400. if Separator <> sepNone then
  1401. begin
  1402. if (CurrentP > SavedP) and (SavedP > PhraseP) then
  1403. CurrentP := SavedP; // there is something before comment or left parenthesis or double quote
  1404. if (Separator in [sepWhitespace,sepComment]) and (SavedP = PhraseP) then
  1405. PhraseP := CurrentP; // skip comments (but not parentheses) and white spaces
  1406. if (CurrentP-PhraseP > 0) or (Separator = sepEnd) then
  1407. begin
  1408. SetString(s, PhraseP, CurrentP-PhraseP);
  1409. Keyword := kwUnknown;
  1410. for K in TKeyword do
  1411. if SameText(s, KeywordNames[K]) then
  1412. begin
  1413. Keyword := K;
  1414. break;
  1415. end;
  1416. case ParsePart of
  1417. ppStart : begin
  1418. Result.StatementType := StrToStatementType(s);
  1419. case Keyword of
  1420. kwWITH : ParsePart := ppWith;
  1421. kwSELECT: ParsePart := ppSelect;
  1422. else break;
  1423. end;
  1424. end;
  1425. ppWith : begin
  1426. // WITH [RECURSIVE] CTE_name [ ( column_names ) ] AS ( CTE_query_definition ) [, ...]
  1427. // { SELECT | INSERT | UPDATE | DELETE } ...
  1428. case Keyword of
  1429. kwSELECT: Result.StatementType := stSelect;
  1430. kwINSERT: Result.StatementType := stInsert;
  1431. kwUPDATE: Result.StatementType := stUpdate;
  1432. kwDELETE: Result.StatementType := stDelete;
  1433. end;
  1434. if Result.StatementType <> stUnknown then break;
  1435. end;
  1436. ppSelect : begin
  1437. if Keyword = kwFROM then
  1438. ParsePart := ppTableName;
  1439. end;
  1440. ppTableName:
  1441. begin
  1442. // Meta-data requests are never updateable
  1443. // and select statements from more than one table
  1444. // and/or derived tables are also not updateable
  1445. if Separator in [sepWhitespace, sepComment, sepDoubleQuote, sepEnd] then
  1446. begin
  1447. Result.TableName := Result.TableName + s;
  1448. Result.Updateable := True;
  1449. end;
  1450. // compound delimited classifier like: "schema name"."table name"
  1451. if not (CurrentP^ in ['.','"']) then
  1452. ParsePart := ppFrom;
  1453. end;
  1454. ppFrom : begin
  1455. if (Keyword in [kwWHERE, kwGROUP, kwORDER, kwLIMIT, kwROWS]) or
  1456. (Separator = sepEnd) then
  1457. begin
  1458. case Keyword of
  1459. kwWHERE: ParsePart := ppWhere;
  1460. kwGROUP: ParsePart := ppGroup;
  1461. kwORDER: ParsePart := ppOrder;
  1462. else ParsePart := ppBogus;
  1463. end;
  1464. Result.WhereStartPos := PhraseP-PSQL+1;
  1465. PStatementPart := CurrentP;
  1466. end
  1467. else
  1468. // joined table or user_defined_function (...)
  1469. if (Keyword = kwJOIN) or (Separator in [sepComma, sepParentheses]) then
  1470. begin
  1471. Result.TableName := '';
  1472. Result.Updateable := False;
  1473. end;
  1474. end;
  1475. ppWhere : begin
  1476. if (Keyword in [kwGROUP, kwORDER, kwLIMIT, kwROWS]) or
  1477. (Separator = sepEnd) then
  1478. begin
  1479. ParsePart := ppBogus;
  1480. Result.WhereStartPos := PStatementPart-PSQL;
  1481. if (Separator = sepEnd) then
  1482. Result.WhereStopPos := CurrentP-PSQL+1
  1483. else
  1484. Result.WhereStopPos := PhraseP-PSQL+1;
  1485. end
  1486. else if (Keyword = kwUNION) then
  1487. begin
  1488. ParsePart := ppBogus;
  1489. Result.Updateable := False;
  1490. end;
  1491. end;
  1492. end; {case}
  1493. end;
  1494. if Separator in [sepComment, sepParentheses, sepDoubleQuote] then
  1495. dec(CurrentP);
  1496. PhraseP := CurrentP+1;
  1497. end
  1498. until CurrentP^=#0;
  1499. end;
  1500. function TSQLConnection.GetAsString(Param: TParam): RawByteString;
  1501. begin
  1502. // converts parameter value to connection charset
  1503. if FCodePage = CP_UTF8 then
  1504. Result := Param.AsUTF8String
  1505. else if (FCodePage = DefaultSystemCodePage) or
  1506. (FCodePage = CP_ACP) or (FCodePage = CP_NONE) then
  1507. Result := Param.AsAnsiString
  1508. else
  1509. begin
  1510. Result := Param.AsAnsiString;
  1511. SetCodePage(Result, FCodePage, True);
  1512. end;
  1513. end;
  1514. function TSQLConnection.GetAsSQLText(Field : TField) : string;
  1515. begin
  1516. if (not assigned(Field)) or Field.IsNull then Result := 'Null'
  1517. else case Field.DataType of
  1518. ftString : Result := QuotedStr(Field.AsString);
  1519. ftDate : Result := '''' + FormatDateTime('yyyy-mm-dd',Field.AsDateTime,FSQLFormatSettings) + '''';
  1520. ftDateTime : Result := '''' + FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz',Field.AsDateTime,FSQLFormatSettings) + '''';
  1521. ftTime : Result := '''' + TimeIntervalToString(Field.AsDateTime) + '''';
  1522. else
  1523. Result := Field.AsString;
  1524. end; {case}
  1525. end;
  1526. function TSQLConnection.GetAsSQLText(Param: TParam) : string;
  1527. begin
  1528. if (not assigned(Param)) or Param.IsNull then Result := 'Null'
  1529. else case Param.DataType of
  1530. ftGuid,
  1531. ftMemo,
  1532. ftFixedChar,
  1533. ftString : Result := QuotedStr(GetAsString(Param));
  1534. ftDate : Result := '''' + FormatDateTime('yyyy-mm-dd', Param.AsDateTime, FSQLFormatSettings) + '''';
  1535. ftTime : Result := '''' + TimeIntervalToString(Param.AsDateTime) + '''';
  1536. ftDateTime : Result := '''' + FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz', Param.AsDateTime, FSQLFormatSettings) + '''';
  1537. ftCurrency,
  1538. ftBcd : Result := CurrToStr(Param.AsCurrency, FSQLFormatSettings);
  1539. ftFloat : Result := FloatToStr(Param.AsFloat, FSQLFormatSettings);
  1540. ftFMTBcd : Result := StringReplace(Param.AsString, DefaultFormatSettings.DecimalSeparator, FSQLFormatSettings.DecimalSeparator, []);
  1541. else
  1542. Result := Param.AsString;
  1543. end; {case}
  1544. end;
  1545. function TSQLConnection.GetHandle: pointer;
  1546. begin
  1547. Result := nil;
  1548. end;
  1549. function TSQLConnection.LogEvent(EventType: TDBEventType): Boolean;
  1550. begin
  1551. Result:=(Assigned(FOnLog) or Assigned(GlobalDBLogHook)) and (EventType in LogEvents);
  1552. end;
  1553. procedure TSQLConnection.LogParams(const AParams: TParams);
  1554. Var
  1555. S : String;
  1556. P : TParam;
  1557. begin
  1558. if not LogEvent(detParamValue) or not Assigned(AParams) then
  1559. Exit;
  1560. For P in AParams do
  1561. begin
  1562. if P.IsNull then
  1563. S:='<NULL>'
  1564. else if (P.DataType in ftBlobTypes) and not (P.DataType in [ftMemo, ftFmtMemo,ftWideMemo]) then
  1565. S:='<BLOB>'
  1566. else
  1567. S:=P.AsString;
  1568. Log(detParamValue,Format(SLogParamValue,[P.Name,S]));
  1569. end;
  1570. end;
  1571. procedure TSQLConnection.Log(EventType: TDBEventType; const Msg: String);
  1572. Var
  1573. M : String;
  1574. begin
  1575. If LogEvent(EventType) then
  1576. begin
  1577. If Assigned(FonLog) then
  1578. FOnLog(Self,EventType,Msg);
  1579. If Assigned(GlobalDBLogHook) then
  1580. begin
  1581. If (Name<>'') then
  1582. M:=Name+' : '+Msg
  1583. else
  1584. M:=ClassName+' : '+Msg;
  1585. GlobalDBLogHook(Self,EventType,M);
  1586. end;
  1587. end;
  1588. end;
  1589. procedure TSQLConnection.RegisterStatement(S: TCustomSQLStatement);
  1590. begin
  1591. FStatements.Add(S);
  1592. end;
  1593. procedure TSQLConnection.UnRegisterStatement(S: TCustomSQLStatement);
  1594. begin
  1595. if Assigned(FStatements) then // Can be nil, when we are destroying and datasets are uncoupled.
  1596. FStatements.Remove(S);
  1597. end;
  1598. function TSQLConnection.CreateCustomQuery(aOwner : TComponent) : TCustomSQLQuery;
  1599. begin
  1600. Result:=TCustomSQLQuery.Create(AOwner);
  1601. end;
  1602. function TSQLConnection.InitialiseUpdateStatement(Query : TCustomSQLQuery; var qry : TCustomSQLQuery): TCustomSQLQuery;
  1603. begin
  1604. if not assigned(qry) then
  1605. begin
  1606. qry := TCustomSQLQuery(TComponentClass(Query.ClassType).Create(Nil));
  1607. qry.ParseSQL := False;
  1608. qry.DataBase := Self;
  1609. qry.Transaction := Query.SQLTransaction;
  1610. qry.Unidirectional:=True;
  1611. qry.UsePrimaryKeyAsKey:=False;
  1612. qry.PacketRecords:=1;
  1613. end;
  1614. Result:=qry;
  1615. end;
  1616. procedure TSQLConnection.AddFieldToUpdateWherePart(var sql_where : string;UpdateMode : TUpdateMode; F : TField);
  1617. begin
  1618. if (pfInKey in F.ProviderFlags)
  1619. or ((UpdateMode = upWhereAll) and (pfInWhere in F.ProviderFlags))
  1620. or ((UpdateMode = UpWhereChanged) and (pfInWhere in F.ProviderFlags) and (F.Value <> F.OldValue)) then
  1621. begin
  1622. if (sql_where<>'') then
  1623. sql_where:=sql_where + ' and ';
  1624. sql_where:= sql_where + '(' + FieldNameQuoteChars[0] + F.FieldName + FieldNameQuoteChars[1];
  1625. if F.OldValue = NULL then
  1626. sql_where := sql_where + ' is null '
  1627. else
  1628. sql_where := sql_where +'= :"' + 'OLD_' + F.FieldName + '"';
  1629. sql_where:=sql_where+') ';
  1630. end;
  1631. end;
  1632. function TSQLConnection.ConstructInsertSQL(Query: TCustomSQLQuery;
  1633. var ReturningClause: Boolean): string;
  1634. var x : integer;
  1635. sql_fields : string;
  1636. sql_values : string;
  1637. returning_fields : String;
  1638. F : TField;
  1639. begin
  1640. sql_fields := '';
  1641. sql_values := '';
  1642. returning_fields := '';
  1643. for x := 0 to Query.Fields.Count -1 do
  1644. begin
  1645. F:=Query.Fields[x];
  1646. if (not F.IsNull) and (pfInUpdate in F.ProviderFlags) and (not F.ReadOnly) then
  1647. begin
  1648. sql_fields := sql_fields + FieldNameQuoteChars[0] + F.FieldName + FieldNameQuoteChars[1] + ',';
  1649. sql_values := sql_values + ':"' + F.FieldName + '",';
  1650. end;
  1651. if ReturningClause and (pfRefreshOnInsert in F.ProviderFlags) then
  1652. returning_fields := returning_fields + FieldNameQuoteChars[0] + F.FieldName + FieldNameQuoteChars[1] + ',';
  1653. end;
  1654. if length(sql_fields) = 0 then
  1655. DatabaseErrorFmt(sNoUpdateFields,['insert'],self);
  1656. setlength(sql_fields,length(sql_fields)-1);
  1657. setlength(sql_values,length(sql_values)-1);
  1658. result := 'insert into ' + Query.FTableName + ' (' + sql_fields + ') values (' + sql_values + ')';
  1659. if ReturningClause then
  1660. begin
  1661. ReturningClause:=length(returning_fields) <> 0 ;
  1662. if ReturningClause then
  1663. begin
  1664. setlength(returning_fields,length(returning_fields)-1);
  1665. Result := Result + ' returning ' + returning_fields;
  1666. end;
  1667. end;
  1668. end;
  1669. function TSQLConnection.ConstructUpdateSQL(Query: TCustomSQLQuery;
  1670. var ReturningClause: Boolean): string;
  1671. var x : integer;
  1672. F : TField;
  1673. sql_set : string;
  1674. sql_where : string;
  1675. returning_fields : String;
  1676. begin
  1677. sql_set := '';
  1678. sql_where := '';
  1679. returning_fields := '';
  1680. for x := 0 to Query.Fields.Count -1 do
  1681. begin
  1682. F:=Query.Fields[x];
  1683. AddFieldToUpdateWherePart(sql_where,Query.UpdateMode,F);
  1684. if (pfInUpdate in F.ProviderFlags) and (not F.ReadOnly) then
  1685. sql_set := sql_set +FieldNameQuoteChars[0] + F.FieldName + FieldNameQuoteChars[1] +'=:"' + F.FieldName + '",';
  1686. if ReturningClause and (pfRefreshOnUpdate in F.ProviderFlags) then
  1687. returning_fields := returning_fields + FieldNameQuoteChars[0] + F.FieldName + FieldNameQuoteChars[1] + ',';
  1688. end;
  1689. if length(sql_set) = 0 then DatabaseErrorFmt(sNoUpdateFields,['update'],self);
  1690. setlength(sql_set,length(sql_set)-1);
  1691. if length(sql_where) = 0 then DatabaseErrorFmt(sNoWhereFields,['update'],self);
  1692. result := 'update ' + Query.FTableName + ' set ' + sql_set + ' where ' + sql_where;
  1693. if ReturningClause then
  1694. begin
  1695. ReturningClause:=length(returning_fields) <> 0 ;
  1696. if ReturningClause then
  1697. begin
  1698. setlength(returning_fields,length(returning_fields)-1);
  1699. Result := Result + ' returning ' + returning_fields;
  1700. end;
  1701. end;
  1702. end;
  1703. function TSQLConnection.ConstructDeleteSQL(Query : TCustomSQLQuery) : string;
  1704. var
  1705. x : integer;
  1706. sql_where : string;
  1707. begin
  1708. sql_where := '';
  1709. for x := 0 to Query.Fields.Count -1 do
  1710. AddFieldToUpdateWherePart(sql_where,Query.UpdateMode, Query.Fields[x]);
  1711. if length(sql_where) = 0 then
  1712. DatabaseErrorFmt(sNoWhereFields,['delete'],self);
  1713. result := 'delete from ' + Query.FTableName + ' where ' + sql_where;
  1714. end;
  1715. function TSQLConnection.ConstructRefreshSQL(Query: TCustomSQLQuery; UpdateKind: TUpdateKind): string;
  1716. Var
  1717. F : TField;
  1718. PF : TProviderFlag;
  1719. Where : String;
  1720. begin
  1721. Result:=Trim(Query.RefreshSQL.Text);
  1722. if (Result='') then
  1723. begin
  1724. Where:='';
  1725. PF:=RefreshFlags[UpdateKind];
  1726. For F in Query.Fields do
  1727. begin
  1728. if PF in F.ProviderFlags then
  1729. begin
  1730. if (Result<>'') then
  1731. Result:=Result+', ';
  1732. if (F.Origin<>'') and (F.Origin<>F.FieldName) then
  1733. Result:=Result+F.Origin+' AS '+F.FieldName
  1734. else
  1735. Result:=Result+FieldNameQuoteChars[0]+F.FieldName+FieldNameQuoteChars[1]
  1736. end;
  1737. if pfInkey in F.ProviderFlags then
  1738. begin
  1739. if (Where<>'') then
  1740. Where:=Where+' AND ';
  1741. Where:=Where+'('+FieldNameQuoteChars[0]+F.FieldName+FieldNameQuoteChars[1]+' = :'+F.FieldName+')';
  1742. end;
  1743. end;
  1744. if (Where='') then
  1745. DatabaseError(SErrNoKeyFieldForRefreshClause,Query);
  1746. Result:='SELECT '+Result+' FROM '+Query.FTableName+' WHERE '+Where;
  1747. end;
  1748. end;
  1749. procedure TSQLConnection.ApplyFieldUpdate(C : TSQLCursor; P : TSQLDBParam; F : TField; UseOldValue : Boolean);
  1750. begin
  1751. if UseOldValue then
  1752. P.AssignFieldValue(F,F.OldValue)
  1753. else
  1754. P.AssignFieldValue(F,F.Value);
  1755. P.FFieldDef:=F.FieldDef;
  1756. end;
  1757. procedure TSQLConnection.ApplyRecUpdate(Query: TCustomSQLQuery; UpdateKind: TUpdateKind);
  1758. var
  1759. qry : TCustomSQLQuery;
  1760. s : string;
  1761. x : integer;
  1762. Fld : TField;
  1763. Par, P : TParam;
  1764. UseOldValue, HasReturningClause : Boolean;
  1765. begin
  1766. qry:=Nil;
  1767. HasReturningClause:=(sqSupportReturning in ConnOptions) and not (sqoRefreshUsingSelect in Query.Options) and (Trim(Query.RefreshSQL.Text)='');
  1768. case UpdateKind of
  1769. ukInsert : begin
  1770. s := Trim(Query.FInsertSQL.Text);
  1771. if s = '' then
  1772. s := ConstructInsertSQL(Query, HasReturningClause)
  1773. else
  1774. HasReturningClause := False;
  1775. qry := InitialiseUpdateStatement(Query, Query.FInsertQry);
  1776. end;
  1777. ukModify : begin
  1778. s := Trim(Query.FUpdateSQL.Text);
  1779. if s = '' then begin
  1780. //if not assigned(Query.FUpdateQry) or (Query.UpdateMode<>upWhereKeyOnly) then // first time or dynamic where part
  1781. s := ConstructUpdateSQL(Query, HasReturningClause);
  1782. end
  1783. else
  1784. HasReturningClause := False;
  1785. qry := InitialiseUpdateStatement(Query, Query.FUpdateQry);
  1786. end;
  1787. ukDelete : begin
  1788. s := Trim(Query.FDeleteSQL.Text);
  1789. if (s='') and (not assigned(Query.FDeleteQry) or (Query.UpdateMode<>upWhereKeyOnly)) then
  1790. s := ConstructDeleteSQL(Query);
  1791. HasReturningClause := False;
  1792. qry := InitialiseUpdateStatement(Query, Query.FDeleteQry);
  1793. end;
  1794. end;
  1795. if (s<>'') and (qry.SQL.Text<>s) then
  1796. qry.SQL.Text:=s; //assign only when changed, to avoid UnPrepare/Prepare
  1797. Assert(qry.SQL.Text<>'');
  1798. for x:=0 to Qry.Params.Count-1 do
  1799. begin
  1800. P:=Qry.Params[x];
  1801. S:=P.Name;
  1802. UseOldValue:=SameText(Copy(S,1,4),'OLD_');
  1803. if UseOldValue then
  1804. begin
  1805. Delete(S,1,4);
  1806. Fld:=Query.FieldByName(S);
  1807. end
  1808. else
  1809. Fld:=Query.FindField(S);
  1810. if Assigned(Fld) then
  1811. ApplyFieldUpdate(Query.Cursor, P as TSQLDBParam, Fld, UseOldValue)
  1812. else
  1813. begin
  1814. // if does not exists field with given name, try look for param
  1815. Par:=Query.Params.FindParam(S);
  1816. if Assigned(Par) then
  1817. P.Assign(Par)
  1818. else
  1819. DatabaseErrorFmt(SFieldNotFound,[S],Query); // same error as raised by FieldByName()
  1820. end;
  1821. end;
  1822. if HasReturningClause then
  1823. begin
  1824. Qry.Close;
  1825. Qry.Open
  1826. end
  1827. else
  1828. Qry.Execute;
  1829. if (scoApplyUpdatesChecksRowsAffected in Options) and (Qry.RowsAffected<>1) then
  1830. begin
  1831. Qry.Close;
  1832. DatabaseErrorFmt(SErrFailedToUpdateRecord, [Qry.RowsAffected], Query);
  1833. end;
  1834. if HasReturningClause then
  1835. Query.ApplyReturningResult(Qry,UpdateKind);
  1836. end;
  1837. function TSQLConnection.RefreshLastInsertID(Query: TCustomSQLQuery; Field: TField): Boolean;
  1838. begin
  1839. Result:=False;
  1840. end;
  1841. procedure TSQLConnection.FreeFldBuffers(cursor: TSQLCursor);
  1842. begin
  1843. // empty
  1844. end;
  1845. function TSQLConnection.StartImplicitTransaction(trans: TSQLHandle; aParams: string): boolean;
  1846. begin
  1847. Result:=False;
  1848. end;
  1849. function TSQLConnection.GetSchemaInfoSQL( SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string) : string;
  1850. begin
  1851. case SchemaType of
  1852. stTables : Result := 'SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE=''BASE TABLE''';
  1853. stColumns : Result := 'SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='+QuotedStr(SchemaObjectName);
  1854. stProcedures: Result := 'SELECT *, ROUTINE_NAME AS PROCEDURE_NAME FROM INFORMATION_SCHEMA.ROUTINES';
  1855. stSchemata : Result := 'SELECT * FROM INFORMATION_SCHEMA.SCHEMATA';
  1856. stSequences : Result := 'SELECT * FROM INFORMATION_SCHEMA.SEQUENCES';
  1857. else DatabaseError(SMetadataUnavailable);
  1858. end;
  1859. end;
  1860. function TSQLConnection.GetNextValueSQL(const SequenceName: string; IncrementBy: Integer): string;
  1861. begin
  1862. Result := 'SELECT NEXT VALUE FOR ' + SequenceName;
  1863. end;
  1864. function TSQLConnection.GetNextValue(const SequenceName: string; IncrementBy: integer): Int64;
  1865. var
  1866. Q: TCustomSQLQuery;
  1867. begin
  1868. Result := 0;
  1869. Q := TCustomSQLQuery.Create(nil);
  1870. try
  1871. Q.DataBase := Self;
  1872. Q.Transaction := Transaction;
  1873. Q.SQL.Text := GetNextValueSQL(SequenceName, IncrementBy);
  1874. Q.Open;
  1875. if not Q.Eof then
  1876. Result := Q.Fields[0].AsLargeInt;
  1877. Q.Close;
  1878. finally
  1879. FreeAndNil(Q);
  1880. end;
  1881. end;
  1882. procedure TSQLConnection.MaybeConnect;
  1883. begin
  1884. If Not Connected then
  1885. begin
  1886. If (scoExplicitConnect in Options) then
  1887. DatabaseErrorFmt(SErrImplicitConnect,[Name]);
  1888. Connected:=True;
  1889. end;
  1890. end;
  1891. procedure TSQLConnection.CreateDB;
  1892. begin
  1893. DatabaseError(SNotSupported);
  1894. end;
  1895. procedure TSQLConnection.DropDB;
  1896. begin
  1897. DatabaseError(SNotSupported);
  1898. end;
  1899. { TSQLTransaction }
  1900. constructor TSQLTransaction.Create(AOwner : TComponent);
  1901. begin
  1902. inherited Create(AOwner);
  1903. FParams := TStringList.Create;
  1904. Action := caRollBack;
  1905. end;
  1906. destructor TSQLTransaction.Destroy;
  1907. begin
  1908. EndTransaction;
  1909. FreeAndNil(FTrans);
  1910. FreeAndNil(FParams);
  1911. inherited Destroy;
  1912. end;
  1913. procedure TSQLTransaction.EndTransaction;
  1914. begin
  1915. Case Action of
  1916. caCommit, caCommitRetaining :
  1917. Commit;
  1918. caNone,
  1919. caRollback, caRollbackRetaining :
  1920. if not (stoUseImplicit in Options) then
  1921. RollBack
  1922. else
  1923. CloseTrans;
  1924. end;
  1925. end;
  1926. procedure TSQLTransaction.SetParams(const AValue: TStringList);
  1927. begin
  1928. FParams.Assign(AValue);
  1929. end;
  1930. function TSQLTransaction.GetSQLConnection: TSQLConnection;
  1931. begin
  1932. Result:=Database as TSQLConnection;
  1933. end;
  1934. procedure TSQLTransaction.SetOptions(AValue: TSQLTransactionOptions);
  1935. begin
  1936. if FOptions=AValue then Exit;
  1937. if (stoUseImplicit in Avalue) and Assigned(SQLConnection) And Not (sqImplicitTransaction in SQLConnection.ConnOptions) then
  1938. DatabaseErrorFmt(SErrNoImplicitTransaction, [SQLConnection.ClassName]);
  1939. FOptions:=AValue;
  1940. end;
  1941. procedure TSQLTransaction.SetSQLConnection(AValue: TSQLConnection);
  1942. begin
  1943. Database:=AValue;
  1944. end;
  1945. Procedure TSQLTransaction.MaybeStartTransaction;
  1946. begin
  1947. if not Active then
  1948. begin
  1949. if (stoExplicitStart in Options) then
  1950. DatabaseErrorFmt(SErrImplictTransactionStart, [Database.Name,Name]);
  1951. StartTransaction;
  1952. end;
  1953. end;
  1954. function TSQLTransaction.GetHandle: Pointer;
  1955. begin
  1956. Result := SQLConnection.GetTransactionHandle(FTrans);
  1957. end;
  1958. Function TSQLTransaction.AllowClose(DS: TDBDataset): Boolean;
  1959. begin
  1960. if (DS is TSQLQuery) then
  1961. Result:=not (sqoKeepOpenOnCommit in TSQLQuery(DS).Options)
  1962. else
  1963. Result:=Inherited AllowClose(DS);
  1964. end;
  1965. procedure TSQLTransaction.Commit;
  1966. begin
  1967. if Active then
  1968. begin
  1969. CloseDataSets;
  1970. If LogEvent(detCommit) then
  1971. Log(detCommit,SCommitting);
  1972. // FTrans=Nil for the case of forced close.
  1973. if (FTrans=Nil) or (stoUseImplicit in Options) or SQLConnection.AttemptCommit(FTrans) then
  1974. begin
  1975. CloseTrans;
  1976. FreeAndNil(FTrans);
  1977. end;
  1978. end;
  1979. end;
  1980. procedure TSQLTransaction.CommitRetaining;
  1981. begin
  1982. if Active then
  1983. begin
  1984. If LogEvent(detCommit) then
  1985. Log(detCommit,SCommitRetaining);
  1986. SQLConnection.CommitRetaining(FTrans);
  1987. end;
  1988. end;
  1989. procedure TSQLTransaction.Rollback;
  1990. begin
  1991. if Active then
  1992. begin
  1993. if (stoUseImplicit in Options) then
  1994. DatabaseError(SErrImplicitNoRollBack);
  1995. CloseDataSets;
  1996. If LogEvent(detRollback) then
  1997. Log(detRollback,SRollingBack);
  1998. // FTrans=Nil for the case of forced close.
  1999. if (FTrans=Nil) or SQLConnection.AttemptRollBack(FTrans) then
  2000. begin
  2001. CloseTrans;
  2002. FreeAndNil(FTrans);
  2003. end;
  2004. end;
  2005. end;
  2006. procedure TSQLTransaction.RollbackRetaining;
  2007. begin
  2008. if Active then
  2009. begin
  2010. if (stoUseImplicit in Options) then
  2011. DatabaseError(SErrImplicitNoRollBack);
  2012. If LogEvent(detRollback) then
  2013. Log(detRollback,SRollBackRetaining);
  2014. SQLConnection.RollBackRetaining(FTrans);
  2015. end;
  2016. end;
  2017. procedure TSQLTransaction.StartTransaction;
  2018. var db : TSQLConnection;
  2019. begin
  2020. if Active then
  2021. DatabaseError(SErrTransAlreadyActive);
  2022. db := SQLConnection;
  2023. if Db = nil then
  2024. DatabaseError(SErrDatabasenAssigned);
  2025. Db.MaybeConnect;
  2026. if not assigned(FTrans) then FTrans := Db.AllocateTransactionHandle;
  2027. if (stoUseImplicit in Options) then
  2028. begin
  2029. if Db.StartImplicitTransaction(FTrans,FParams.CommaText) then
  2030. OpenTrans
  2031. end
  2032. else
  2033. begin
  2034. if Db.StartDBTransaction(FTrans,FParams.CommaText) then
  2035. OpenTrans
  2036. end;
  2037. end;
  2038. Procedure TSQLTransaction.SetDatabase(Value: TDatabase);
  2039. begin
  2040. If Value<>Database then
  2041. begin
  2042. if Assigned(Value) and not (Value is TSQLConnection) then
  2043. DatabaseErrorFmt(SErrNotASQLConnection, [Value.Name], Self);
  2044. CheckInactive;
  2045. if (stoUseImplicit in Options) and Assigned(Value) and Not (sqImplicitTransaction in TSQLConnection(Value).ConnOptions) then
  2046. DatabaseErrorFmt(SErrNoImplicitTransaction, [Value.ClassName]);
  2047. If Assigned(Database) then
  2048. if SQLConnection.Transaction = Self then SQLConnection.Transaction := nil;
  2049. inherited;
  2050. If Assigned(Database) and not (csLoading in ComponentState) then
  2051. If SQLConnection.Transaction = Nil then SQLConnection.Transaction := Self;
  2052. end;
  2053. end;
  2054. Function TSQLTransaction.LogEvent(EventType: TDBEventType): Boolean;
  2055. begin
  2056. Result:=Assigned(Database) and SQLConnection.LogEvent(EventType);
  2057. end;
  2058. Procedure TSQLTransaction.Log(EventType: TDBEventType; Const Msg: String);
  2059. Var
  2060. M : String;
  2061. begin
  2062. If LogEvent(EventType) then
  2063. begin
  2064. If (Name<>'') then
  2065. M:=Name+' : '+Msg
  2066. else
  2067. M:=Msg;
  2068. SQLConnection.Log(EventType,M);
  2069. end;
  2070. end;
  2071. { TSQLSequence }
  2072. constructor TSQLSequence.Create(AQuery: TCustomSQLQuery);
  2073. begin
  2074. inherited Create;
  2075. FQuery := AQuery;
  2076. FApplyEvent := saeOnNewRecord;
  2077. FIncrementBy := 1;
  2078. end;
  2079. procedure TSQLSequence.Assign(Source: TPersistent);
  2080. var SourceSequence: TSQLSequence;
  2081. begin
  2082. if Source is TSQLSequence then
  2083. begin
  2084. SourceSequence := TSQLSequence(Source);
  2085. FFieldName := SourceSequence.FieldName;
  2086. FSequenceName := SourceSequence.SequenceName;
  2087. FIncrementBy := SourceSequence.IncrementBy;
  2088. FApplyEvent := SourceSequence.ApplyEvent;
  2089. end
  2090. else
  2091. inherited;
  2092. end;
  2093. procedure TSQLSequence.Apply;
  2094. var Field: TField;
  2095. begin
  2096. if Assigned(FQuery) and (FSequenceName<>'') and (FFieldName<>'') then
  2097. begin
  2098. Field := FQuery.FindField(FFieldName);
  2099. if Assigned(Field) and Field.IsNull then
  2100. Field.AsLargeInt := GetNextValue;
  2101. end;
  2102. end;
  2103. function TSQLSequence.GetNextValue: Int64;
  2104. begin
  2105. if (FQuery=Nil) or (FQuery.SQLConnection=Nil) then
  2106. DatabaseError(SErrDatabasenAssigned);
  2107. Result := FQuery.SQLConnection.GetNextValue(FSequenceName, FIncrementBy);
  2108. end;
  2109. Type
  2110. { TQuerySQLStatement }
  2111. TQuerySQLStatement = Class(TCustomSQLStatement)
  2112. protected
  2113. FQuery : TCustomSQLQuery;
  2114. function CreateParams: TSQLDBParams; override;
  2115. Function CreateDataLink : TDataLink; override;
  2116. Function GetSchemaType : TSchemaType; override;
  2117. Function GetSchemaObjectName : String; override;
  2118. Function GetSchemaPattern: String; override;
  2119. procedure GetStatementInfo(var ASQL: String; out Info: TSQLStatementInfo); override;
  2120. procedure OnChangeSQL(Sender : TObject); override;
  2121. public
  2122. constructor Create(AOwner: TComponent); override;
  2123. end;
  2124. { TQuerySQLStatement }
  2125. constructor TQuerySQLStatement.Create(AOwner: TComponent);
  2126. begin
  2127. FQuery:=TCustomSQLQuery(AOwner);
  2128. inherited Create(AOwner);
  2129. end;
  2130. function TQuerySQLStatement.CreateDataLink: TDataLink;
  2131. begin
  2132. Result:=TMasterParamsDataLink.Create(FQuery);
  2133. end;
  2134. function TQuerySQLStatement.CreateParams: TSQLDBParams;
  2135. begin
  2136. Result:=FQuery.CreateParams;
  2137. end;
  2138. function TQuerySQLStatement.GetSchemaType: TSchemaType;
  2139. begin
  2140. if Assigned(FQuery) then
  2141. Result:=FQuery.FSchemaType
  2142. else
  2143. Result:=stNoSchema;
  2144. end;
  2145. function TQuerySQLStatement.GetSchemaObjectName: String;
  2146. begin
  2147. if Assigned(FQuery) then
  2148. Result:=FQuery.FSchemaObjectname
  2149. else
  2150. Result:=inherited GetSchemaObjectName;
  2151. end;
  2152. function TQuerySQLStatement.GetSchemaPattern: String;
  2153. begin
  2154. if Assigned(FQuery) then
  2155. Result:=FQuery.FSchemaPattern
  2156. else
  2157. Result:=inherited GetSchemaPattern;
  2158. end;
  2159. procedure TQuerySQLStatement.GetStatementInfo(var ASQL: String; out Info: TSQLStatementInfo);
  2160. begin
  2161. inherited GetStatementInfo(ASQL, Info);
  2162. If Assigned(FQuery) then
  2163. // Note: practical side effect of switch off ParseSQL is that UpdateServerIndexDefs is bypassed
  2164. // which is used as performance tuning option
  2165. if (FQuery.FSchemaType = stNoSchema) and FParseSQL then
  2166. begin
  2167. FQuery.FUpdateable:=Info.Updateable;
  2168. FQuery.FTableName:=Info.TableName;
  2169. FQuery.FWhereStartPos:=Info.WhereStartPos;
  2170. FQuery.FWhereStopPos:=Info.WhereStopPos;
  2171. if FQuery.ServerFiltered then
  2172. ASQL:=FQuery.AddFilter(ASQL);
  2173. end
  2174. else
  2175. begin
  2176. FQuery.FUpdateable:=false;
  2177. FQuery.FTableName:='';
  2178. FQuery.FWhereStartPos:=0;
  2179. FQuery.FWhereStopPos:=0;
  2180. end;
  2181. end;
  2182. procedure TQuerySQLStatement.OnChangeSQL(Sender: TObject);
  2183. begin
  2184. UnPrepare;
  2185. inherited OnChangeSQL(Sender);
  2186. If ParamCheck and Assigned(FDataLink) then
  2187. (FDataLink as TMasterParamsDataLink).RefreshParamNames;
  2188. FQuery.ServerIndexDefs.Updated:=false;
  2189. end;
  2190. { TCustomSQLQuery }
  2191. Function TCustomSQLQuery.CreateSQLStatement(aOwner : TComponent) : TCustomSQLStatement;
  2192. begin
  2193. Result:=TQuerySQLStatement.Create(Self);
  2194. end;
  2195. constructor TCustomSQLQuery.Create(AOwner : TComponent);
  2196. begin
  2197. inherited Create(AOwner);
  2198. FStatement:=CreateSQLStatement(Self);
  2199. FInsertSQL := TStringList.Create;
  2200. FInsertSQL.OnChange := @OnChangeModifySQL;
  2201. FUpdateSQL := TStringList.Create;
  2202. FUpdateSQL.OnChange := @OnChangeModifySQL;
  2203. FDeleteSQL := TStringList.Create;
  2204. FDeleteSQL.OnChange := @OnChangeModifySQL;
  2205. FRefreshSQL := TStringList.Create;
  2206. FRefreshSQL.OnChange := @OnChangeModifySQL;
  2207. FSequence := TSQLSequence.Create(Self);
  2208. FServerIndexDefs := TServerIndexDefs.Create(Self);
  2209. FServerFiltered := False;
  2210. FServerFilterText := '';
  2211. FSchemaType:=stNoSchema;
  2212. FSchemaObjectName:='';
  2213. FSchemaPattern:='';
  2214. // Delphi has upWhereAll as default, but since strings and oldvalue's don't work yet
  2215. // (variants) set it to upWhereKeyOnly
  2216. FUpdateMode := upWhereKeyOnly;
  2217. FUsePrimaryKeyAsKey := True;
  2218. end;
  2219. destructor TCustomSQLQuery.Destroy;
  2220. begin
  2221. if Active then Close;
  2222. UnPrepare;
  2223. FreeAndNil(FStatement);
  2224. FreeAndNil(FInsertSQL);
  2225. FreeAndNil(FUpdateSQL);
  2226. FreeAndNil(FDeleteSQL);
  2227. FreeAndNil(FRefreshSQL);
  2228. FreeAndNil(FSequence);
  2229. FreeAndNil(FServerIndexDefs);
  2230. inherited Destroy;
  2231. end;
  2232. function TCustomSQLQuery.ParamByName(const AParamName: String): TParam;
  2233. begin
  2234. Result:=Params.ParamByName(AParamName);
  2235. end;
  2236. procedure TCustomSQLQuery.OnChangeModifySQL(Sender : TObject);
  2237. begin
  2238. CheckInactive;
  2239. end;
  2240. procedure TCustomSQLQuery.SetDatabase(Value : TDatabase);
  2241. var DB : TSQLConnection;
  2242. begin
  2243. if Database = Value then Exit;
  2244. if Assigned(Value) and not (Value is TSQLConnection) then
  2245. DatabaseErrorFmt(SErrNotASQLConnection, [Value.Name], Self);
  2246. UnPrepare;
  2247. DB := TSQLConnection(Value);
  2248. If Assigned(FStatement) then
  2249. FStatement.Database := DB;
  2250. inherited;
  2251. if Assigned(DB) and Assigned(DB.Transaction) and (not Assigned(Transaction) or (Transaction.DataBase<>Database)) then
  2252. Transaction := DB.Transaction;
  2253. end;
  2254. procedure TCustomSQLQuery.SetTransaction(Value: TDBTransaction);
  2255. begin
  2256. if Transaction = Value then Exit;
  2257. UnPrepare;
  2258. inherited;
  2259. If Assigned(FStatement) then
  2260. FStatement.Transaction := TSQLTransaction(Value);
  2261. If Assigned(Transaction) and Assigned(Transaction.DataBase) and (Database<>Transaction.DataBase) then
  2262. Database := Transaction.Database;
  2263. end;
  2264. function TCustomSQLQuery.IsPrepared: Boolean;
  2265. begin
  2266. if Assigned(Fstatement) then
  2267. Result := FStatement.Prepared
  2268. else
  2269. Result := False;
  2270. end;
  2271. function TCustomSQLQuery.AddFilter(SQLstr: string): string;
  2272. begin
  2273. if (FWhereStartPos > 0) and (FWhereStopPos > 0) then
  2274. begin
  2275. system.insert('(',SQLstr,FWhereStartPos+1);
  2276. system.insert(')',SQLstr,FWhereStopPos+1);
  2277. end;
  2278. if FWhereStartPos = 0 then
  2279. SQLstr := SQLstr + ' where (' + ServerFilter + ')'
  2280. else if FWhereStopPos > 0 then
  2281. system.insert(' and ('+ServerFilter+') ',SQLstr,FWhereStopPos+2)
  2282. else
  2283. system.insert(' where ('+ServerFilter+') ',SQLstr,FWhereStartPos);
  2284. Result := SQLstr;
  2285. end;
  2286. function TCustomSQLQuery.NeedRefreshRecord(UpdateKind: TUpdateKind): Boolean;
  2287. Var
  2288. PF : TProviderFlag;
  2289. I : Integer;
  2290. DoReturning : Boolean;
  2291. begin
  2292. Result:=(Trim(FRefreshSQL.Text)<>'');
  2293. DoReturning:=(sqSupportReturning in SQLConnection.ConnOptions) and not (sqoRefreshUsingSelect in Options);
  2294. if Not (Result or DoReturning) then
  2295. begin
  2296. PF:=RefreshFlags[UpdateKind];
  2297. I:=0;
  2298. While (Not Result) and (I<Fields.Count) do
  2299. begin
  2300. Result:=PF in Fields[i].ProviderFlags;
  2301. Inc(I);
  2302. end;
  2303. end;
  2304. end;
  2305. function TCustomSQLQuery.RefreshRecord(UpdateKind: TUpdateKind): Boolean;
  2306. Var
  2307. Q : TCustomSQLQuery;
  2308. P : TParam;
  2309. F,FD : TField;
  2310. N : String;
  2311. begin
  2312. Result:=False;
  2313. Q:=TCustomSQLQuery.Create(Nil);
  2314. try
  2315. Q.Database:=Self.Database;
  2316. Q.Transaction:=Self.Transaction;
  2317. Q.SQL.Text:=SQLConnection.ConstructRefreshSQL(Self,UpdateKind);
  2318. For P in Q.Params do
  2319. begin
  2320. N:=P.Name;
  2321. If CompareText(Copy(N,1,4),'OLD_')=0 then
  2322. system.Delete(N,1,4);
  2323. F:=Fields.FindField(N);
  2324. if Assigned(F) then
  2325. P.AssignField(F);
  2326. end;
  2327. Q.Open;
  2328. try
  2329. if (Q.EOF and Q.BOF) then
  2330. DatabaseError(SErrRefreshEmptyResult,Self)
  2331. else
  2332. begin
  2333. if Q.RecordCount<>1 then
  2334. DatabaseErrorFmt(SErrRefreshNotSingleton,[Q.RecordCount],Self);
  2335. For F in Q.Fields do
  2336. begin
  2337. FD:=Fields.FindField(F.FieldName);
  2338. if Assigned(FD) then
  2339. begin
  2340. FD.Assign(F);
  2341. Result:=True; // We could check if the new value differs from the old, but we won't.
  2342. end;
  2343. end;
  2344. end
  2345. finally
  2346. Q.Close;
  2347. end;
  2348. finally
  2349. Q.Free;
  2350. end;
  2351. end;
  2352. procedure TCustomSQLQuery.ApplyReturningResult(Q: TCustomSQLQuery; UpdateKind : TUpdateKind);
  2353. Var
  2354. S : TDataSetState;
  2355. refreshFlag : TProviderFlag;
  2356. F : TField;
  2357. begin
  2358. RefreshFlag:=RefreshFlags[UpdateKind];
  2359. S:=SetTempState(dsRefreshFields);
  2360. try
  2361. For F in Fields do
  2362. if RefreshFlag in F.ProviderFlags then
  2363. F.Assign(Q.FieldByName(F.FieldName));
  2364. finally
  2365. RestoreState(S);
  2366. end;
  2367. end;
  2368. procedure TCustomSQLQuery.ApplyFilter;
  2369. begin
  2370. FStatement.Unprepare;
  2371. FStatement.DoPrepare;
  2372. FStatement.DoExecute;
  2373. InternalRefresh;
  2374. First;
  2375. end;
  2376. procedure TCustomSQLQuery.SetActive(Value: Boolean);
  2377. begin
  2378. inherited SetActive(Value);
  2379. // The query is UnPrepared, so that if a transaction closes all datasets
  2380. // they also get unprepared
  2381. if not Value and IsPrepared then UnPrepare;
  2382. end;
  2383. procedure TCustomSQLQuery.SetServerFiltered(Value: Boolean);
  2384. begin
  2385. if Value and not ParseSQL then
  2386. DatabaseErrorFmt(SNoParseSQL,['Filtering ']);
  2387. if (ServerFiltered <> Value) then
  2388. begin
  2389. FServerFiltered := Value;
  2390. if Active then ApplyFilter;
  2391. end;
  2392. end;
  2393. procedure TCustomSQLQuery.SetServerFilterText(const Value: string);
  2394. begin
  2395. if Value <> ServerFilter then
  2396. begin
  2397. FServerFilterText := Value;
  2398. if Active then ApplyFilter;
  2399. end;
  2400. end;
  2401. procedure TCustomSQLQuery.Prepare;
  2402. begin
  2403. FStatement.Prepare;
  2404. if Assigned(FStatement.FCursor) then
  2405. with FStatement.FCursor do
  2406. FInitFieldDef := FSelectable;
  2407. end;
  2408. procedure TCustomSQLQuery.UnPrepare;
  2409. begin
  2410. CheckInactive;
  2411. If Assigned(FStatement) then
  2412. FStatement.Unprepare;
  2413. end;
  2414. procedure TCustomSQLQuery.FreeFldBuffers;
  2415. begin
  2416. if assigned(Cursor) then
  2417. SQLConnection.FreeFldBuffers(Cursor);
  2418. end;
  2419. function TCustomSQLQuery.GetParamCheck: Boolean;
  2420. begin
  2421. Result:=FStatement.ParamCheck;
  2422. end;
  2423. function TCustomSQLQuery.GetParams: TParams;
  2424. begin
  2425. Result:=FStatement.Params;
  2426. end;
  2427. function TCustomSQLQuery.GetParseSQL: Boolean;
  2428. begin
  2429. Result:=FStatement.ParseSQL;
  2430. end;
  2431. function TCustomSQLQuery.GetServerIndexDefs: TServerIndexDefs;
  2432. begin
  2433. Result := FServerIndexDefs;
  2434. end;
  2435. function TCustomSQLQuery.GetSQL: TStringList;
  2436. begin
  2437. Result:=TStringList(Fstatement.SQL);
  2438. end;
  2439. function TCustomSQLQuery.GetSQLConnection: TSQLConnection;
  2440. begin
  2441. Result:=Database as TSQLConnection;
  2442. end;
  2443. function TCustomSQLQuery.GetSQLTransaction: TSQLTransaction;
  2444. begin
  2445. Result:=Transaction as TSQLTransaction;
  2446. end;
  2447. function TCustomSQLQuery.Cursor: TSQLCursor;
  2448. begin
  2449. Result:=FStatement.Cursor;
  2450. end;
  2451. function TCustomSQLQuery.Fetch : boolean;
  2452. begin
  2453. if Not Assigned(Cursor) then
  2454. Exit;
  2455. if not Cursor.FSelectable then
  2456. Exit;
  2457. If LogEvent(detFetch) then
  2458. Log(detFetch,FStatement.FServerSQL);
  2459. if not FIsEof then FIsEOF := not SQLConnection.Fetch(Cursor);
  2460. Result := not FIsEOF;
  2461. end;
  2462. procedure TCustomSQLQuery.Execute;
  2463. begin
  2464. FStatement.Execute;
  2465. end;
  2466. function TCustomSQLQuery.RowsAffected: TRowsCount;
  2467. begin
  2468. Result:=FStatement.RowsAffected;
  2469. end;
  2470. function TCustomSQLQuery.LoadField(FieldDef : TFieldDef; buffer : pointer; out CreateBlob : boolean) : boolean;
  2471. begin
  2472. Result := SQLConnection.LoadField(Cursor, FieldDef, buffer, CreateBlob);
  2473. // disable deferred blob loading for "disconnected" datasets
  2474. if Result and (FieldDef.DataType in ftBlobTypes) and (sqoKeepOpenOnCommit in Options) then
  2475. CreateBlob:=True
  2476. end;
  2477. procedure TCustomSQLQuery.LoadBlobIntoBuffer(FieldDef: TFieldDef;
  2478. ABlobBuf: PBufBlobField);
  2479. begin
  2480. SQLConnection.LoadBlobIntoBuffer(FieldDef, ABlobBuf, Cursor,SQLTransaction);
  2481. end;
  2482. procedure TCustomSQLQuery.InternalAddRecord(Buffer: Pointer; AAppend: Boolean);
  2483. begin
  2484. // not implemented - sql dataset
  2485. end;
  2486. procedure TCustomSQLQuery.InternalClose;
  2487. begin
  2488. if assigned(Cursor) then
  2489. begin
  2490. if Cursor.FSelectable then
  2491. FreeFldBuffers;
  2492. // Some SQLConnections does not support statement [un]preparation,
  2493. // so let them do cleanup f.e. cancel pending queries and/or free resultset
  2494. if not Prepared then FStatement.DoUnprepare;
  2495. end;
  2496. if DefaultFields then
  2497. DestroyFields;
  2498. FIsEOF := False;
  2499. if assigned(FUpdateQry) then FreeAndNil(FUpdateQry);
  2500. if assigned(FInsertQry) then FreeAndNil(FInsertQry);
  2501. if assigned(FDeleteQry) then FreeAndNil(FDeleteQry);
  2502. // FRecordSize := 0;
  2503. inherited InternalClose;
  2504. end;
  2505. procedure TCustomSQLQuery.InternalInitFieldDefs;
  2506. begin
  2507. if FLoadingFieldDefs then
  2508. Exit;
  2509. FLoadingFieldDefs := True;
  2510. try
  2511. FieldDefs.Clear;
  2512. Prepare;
  2513. SQLConnection.AddFieldDefs(Cursor,FieldDefs);
  2514. finally
  2515. FLoadingFieldDefs := False;
  2516. if assigned(Cursor) then Cursor.FInitFieldDef := False;
  2517. end;
  2518. end;
  2519. procedure TCustomSQLQuery.InternalOpen;
  2520. var counter, fieldc : integer;
  2521. F : TField;
  2522. IndexFields : TStrings;
  2523. begin
  2524. if IsReadFromPacket then
  2525. begin
  2526. // When we read from file there is no need for Cursor, also note that Database may not be assigned
  2527. //FStatement.AllocateCursor;
  2528. //Cursor.FSelectable:=True;
  2529. //Cursor.FStatementType:=stSelect;
  2530. FUpdateable:=True;
  2531. end
  2532. else
  2533. begin
  2534. Prepare;
  2535. if not Cursor.FSelectable then
  2536. DatabaseError(SErrNoSelectStatement,Self);
  2537. // Call UpdateServerIndexDefs before Execute, to avoid problems with connections
  2538. // which do not allow processing multiple recordsets at a time. (Microsoft
  2539. // calls this MARS, see bug 13241)
  2540. if DefaultFields and FUpdateable and FusePrimaryKeyAsKey and (not IsUniDirectional) then
  2541. UpdateServerIndexDefs;
  2542. Execute;
  2543. if not Cursor.FSelectable then
  2544. DatabaseError(SErrNoSelectStatement,Self);
  2545. // InternalInitFieldDef is only called after a prepare. i.e. not twice if
  2546. // a dataset is opened - closed - opened.
  2547. if Cursor.FInitFieldDef then InternalInitFieldDefs;
  2548. if DefaultFields then
  2549. begin
  2550. CreateFields;
  2551. if FUpdateable and FusePrimaryKeyAsKey and (not IsUniDirectional) then
  2552. for counter := 0 to ServerIndexDefs.Count-1 do
  2553. if ixPrimary in ServerIndexDefs[counter].Options then
  2554. begin
  2555. IndexFields := TStringList.Create;
  2556. ExtractStrings([';'],[' '],pchar(ServerIndexDefs[counter].Fields),IndexFields);
  2557. for fieldc := 0 to IndexFields.Count-1 do
  2558. begin
  2559. F := FindField(IndexFields[fieldc]);
  2560. if F <> nil then
  2561. F.ProviderFlags := F.ProviderFlags + [pfInKey];
  2562. end;
  2563. IndexFields.Free;
  2564. end;
  2565. end;
  2566. end;
  2567. BindFields(True);
  2568. if not ReadOnly and not FUpdateable and (FSchemaType=stNoSchema) then
  2569. begin
  2570. if (trim(FDeleteSQL.Text) <> '') or (trim(FUpdateSQL.Text) <> '') or
  2571. (trim(FInsertSQL.Text) <> '') then FUpdateable := True;
  2572. end;
  2573. inherited InternalOpen;
  2574. end;
  2575. procedure TCustomSQLQuery.InternalRefresh;
  2576. begin
  2577. if (ChangeCount>0) and (sqoCancelUpdatesOnRefresh in Options) then
  2578. CancelUpdates;
  2579. inherited InternalRefresh;
  2580. end;
  2581. // public part
  2582. procedure TCustomSQLQuery.ExecSQL;
  2583. begin
  2584. try
  2585. Prepare;
  2586. Execute;
  2587. If sqoAutoCommit in Options then
  2588. begin
  2589. // Retrieve rows affected
  2590. FStatement.RowsAffected;
  2591. SQLTransaction.Commit;
  2592. end;
  2593. finally
  2594. // Cursor has to be assigned, or else the prepare went wrong before PrepareStatment was
  2595. // called, so UnPrepareStatement shoudn't be called either
  2596. // Don't deallocate cursor; f.e. RowsAffected is requested later
  2597. if not Prepared and (assigned(Database)) and (assigned(Cursor)) then SQLConnection.UnPrepareStatement(Cursor);
  2598. end;
  2599. end;
  2600. procedure TCustomSQLQuery.ApplyUpdates(MaxErrors: Integer);
  2601. begin
  2602. inherited ApplyUpdates(MaxErrors);
  2603. If sqoAutoCommit in Options then
  2604. begin
  2605. // Retrieve rows affected for last update.
  2606. FStatement.RowsAffected;
  2607. SQLTransaction.Commit;
  2608. end;
  2609. end;
  2610. procedure TCustomSQLQuery.Post;
  2611. begin
  2612. inherited Post;
  2613. If (sqoAutoApplyUpdates in Options) then
  2614. ApplyUpdates;
  2615. end;
  2616. procedure TCustomSQLQuery.Delete;
  2617. begin
  2618. inherited Delete;
  2619. If (sqoAutoApplyUpdates in Options) then
  2620. ApplyUpdates;
  2621. end;
  2622. procedure TCustomSQLQuery.SetReadOnly(AValue : Boolean);
  2623. begin
  2624. CheckInactive;
  2625. inherited SetReadOnly(AValue);
  2626. end;
  2627. procedure TCustomSQLQuery.SetParseSQL(AValue : Boolean);
  2628. begin
  2629. CheckInactive;
  2630. FStatement.ParseSQL:=AValue;
  2631. if not AValue then
  2632. FServerFiltered := False;
  2633. end;
  2634. procedure TCustomSQLQuery.SetSQL(const AValue: TStringList);
  2635. begin
  2636. FStatement.SQL.Assign(AValue);
  2637. end;
  2638. procedure TCustomSQLQuery.SetUsePrimaryKeyAsKey(AValue : Boolean);
  2639. begin
  2640. if not Active then FusePrimaryKeyAsKey := AValue
  2641. else
  2642. begin
  2643. // Just temporary, this should be possible in the future
  2644. DatabaseError(SActiveDataset);
  2645. end;
  2646. end;
  2647. procedure TCustomSQLQuery.UpdateServerIndexDefs;
  2648. begin
  2649. FServerIndexDefs.Clear;
  2650. if assigned(DataBase) and (FTableName<>'') then
  2651. SQLConnection.UpdateIndexDefs(ServerIndexDefs,FTableName);
  2652. end;
  2653. function TCustomSQLQuery.NeedLastInsertID: TField;
  2654. Var
  2655. I : Integer;
  2656. begin
  2657. Result:=Nil;
  2658. if sqLastInsertID in SQLConnection.ConnOptions then
  2659. begin
  2660. I:=0;
  2661. While (Result=Nil) and (I<Fields.Count) do
  2662. begin
  2663. Result:=Fields[i];
  2664. if (Result.DataType<>ftAutoInc) or not Result.IsNull then
  2665. Result:=Nil;
  2666. Inc(I);
  2667. end;
  2668. end
  2669. end;
  2670. function TCustomSQLQuery.RefreshLastInsertID(Field: TField): Boolean;
  2671. begin
  2672. Result:=SQLConnection.RefreshLastInsertID(Self, Field);
  2673. end;
  2674. procedure TCustomSQLQuery.ApplyRecUpdate(UpdateKind: TUpdateKind);
  2675. Var
  2676. DoRefresh : Boolean;
  2677. LastIDField : TField;
  2678. S : TDataSetState;
  2679. begin
  2680. // Moved to connection: the SQLConnection always has more information about types etc.
  2681. // than SQLQuery itself.
  2682. SQLConnection.ApplyRecUpdate(Self,UpdateKind);
  2683. if UpdateKind=ukInsert then
  2684. LastIDField:=NeedLastInsertID
  2685. else
  2686. LastIDField:=nil;
  2687. DoRefresh:=(UpdateKind in [ukModify,ukInsert]) and NeedRefreshRecord(UpdateKind);
  2688. if assigned(LastIDField) or DoRefresh then
  2689. begin
  2690. // updates fields directly in record buffer of TBufDataSet
  2691. // TDataSet buffers are resynchronized at end of ApplyUpdates process
  2692. S:=SetTempState(dsRefreshFields);
  2693. try
  2694. if assigned(LastIDField) then
  2695. RefreshLastInsertID(LastIDField);
  2696. if DoRefresh then
  2697. RefreshRecord(UpdateKind);
  2698. finally
  2699. RestoreState(S);
  2700. end;
  2701. end;
  2702. end;
  2703. procedure TCustomSQLQuery.SetPacketRecords(aValue: integer);
  2704. begin
  2705. if (AValue=PacketRecords) then exit;
  2706. if (AValue<>-1) and (sqoKeepOpenOnCommit in Options) then
  2707. DatabaseError(SErrDisconnectedPacketRecords);
  2708. Inherited SetPacketRecords(aValue);
  2709. end;
  2710. function TCustomSQLQuery.GetCanModify: Boolean;
  2711. begin
  2712. // the test for assigned(Cursor) is needed for the case that the dataset isn't opened
  2713. if assigned(Cursor) and (Cursor.FStatementType = stSelect) then
  2714. Result:= FUpdateable and (not ReadOnly) and (not IsUniDirectional)
  2715. else
  2716. Result := False;
  2717. end;
  2718. procedure TCustomSQLQuery.SetUpdateMode(AValue : TUpdateMode);
  2719. begin
  2720. FUpdateMode := AValue;
  2721. end;
  2722. procedure TCustomSQLQuery.SetSchemaInfo( ASchemaType : TSchemaType; ASchemaObjectName, ASchemaPattern : string);
  2723. begin
  2724. FSchemaType:=ASchemaType;
  2725. FSchemaObjectName:=ASchemaObjectName;
  2726. FSchemaPattern:=ASchemaPattern;
  2727. end;
  2728. procedure TCustomSQLQuery.BeforeRefreshOpenCursor;
  2729. begin
  2730. // This is only necessary because TIBConnection can not re-open a
  2731. // prepared cursor. In fact this is wrong, but has never led to
  2732. // problems because in SetActive(false) queries are always
  2733. // unprepared. (which is also wrong, but has to be fixed later)
  2734. if IsPrepared then with SQLConnection do
  2735. UnPrepareStatement(Cursor);
  2736. end;
  2737. function TCustomSQLQuery.CreateParams: TSQLDBParams;
  2738. begin
  2739. Result:=TSQLDBParams.Create(Nil);
  2740. end;
  2741. function TCustomSQLQuery.LogEvent(EventType: TDBEventType): Boolean;
  2742. begin
  2743. Result:=Assigned(Database) and SQLConnection.LogEvent(EventType);
  2744. end;
  2745. procedure TCustomSQLQuery.Log(EventType: TDBEventType; const Msg: String);
  2746. Var
  2747. M : String;
  2748. begin
  2749. If LogEvent(EventType) then
  2750. begin
  2751. M:=Msg;
  2752. If (Name<>'') then
  2753. M:=Name+' : '+M;
  2754. SQLConnection.Log(EventType,M);
  2755. end;
  2756. end;
  2757. class function TCustomSQLQuery.FieldDefsClass: TFieldDefsClass;
  2758. begin
  2759. Result:=TSQLDBFieldDefs;
  2760. end;
  2761. function TCustomSQLQuery.GetStatementType : TStatementType;
  2762. begin
  2763. if Assigned(Cursor) then
  2764. Result:=Cursor.FStatementType
  2765. else
  2766. Result:=stUnknown;
  2767. end;
  2768. procedure TCustomSQLQuery.SetParamCheck(AValue: Boolean);
  2769. begin
  2770. FStatement.ParamCheck:=AValue;
  2771. end;
  2772. procedure TCustomSQLQuery.SetOptions(AValue: TSQLQueryOptions);
  2773. begin
  2774. if FOptions=AValue then Exit;
  2775. CheckInactive;
  2776. FOptions:=AValue;
  2777. if sqoKeepOpenOnCommit in FOptions then
  2778. PacketRecords:=-1;
  2779. end;
  2780. procedure TCustomSQLQuery.SetSQLConnection(AValue: TSQLConnection);
  2781. begin
  2782. Database:=AValue;
  2783. end;
  2784. procedure TCustomSQLQuery.SetSQLTransaction(AValue: TSQLTransaction);
  2785. begin
  2786. Transaction:=AValue;
  2787. end;
  2788. procedure TCustomSQLQuery.SetInsertSQL(const AValue: TStringList);
  2789. begin
  2790. FInsertSQL.Assign(AValue);
  2791. end;
  2792. procedure TCustomSQLQuery.SetUpdateSQL(const AValue: TStringList);
  2793. begin
  2794. FUpdateSQL.Assign(AValue);
  2795. end;
  2796. procedure TCustomSQLQuery.SetDeleteSQL(const AValue: TStringList);
  2797. begin
  2798. FDeleteSQL.Assign(AValue);
  2799. end;
  2800. procedure TCustomSQLQuery.SetRefreshSQL(const AValue: TStringList);
  2801. begin
  2802. FRefreshSQL.Assign(AValue);
  2803. end;
  2804. procedure TCustomSQLQuery.SetParams(AValue: TParams);
  2805. begin
  2806. FStatement.Params.Assign(AValue);
  2807. end;
  2808. procedure TCustomSQLQuery.SetDataSource(AValue: TDataSource);
  2809. Var
  2810. DS : TDataSource;
  2811. begin
  2812. DS:=DataSource;
  2813. If (AValue<>DS) then
  2814. begin
  2815. If Assigned(AValue) and (AValue.Dataset=Self) then
  2816. DatabaseError(SErrCircularDataSourceReferenceNotAllowed,Self);
  2817. If Assigned(DS) then
  2818. DS.RemoveFreeNotification(Self);
  2819. FStatement.DataSource:=AValue;
  2820. end;
  2821. end;
  2822. function TCustomSQLQuery.GetDataSource: TDataSource;
  2823. begin
  2824. If Assigned(FStatement) then
  2825. Result:=FStatement.DataSource
  2826. else
  2827. Result:=Nil;
  2828. end;
  2829. procedure TCustomSQLQuery.Notification(AComponent: TComponent; Operation: TOperation);
  2830. begin
  2831. Inherited;
  2832. If (Operation=opRemove) and (AComponent=DataSource) then
  2833. DataSource:=Nil;
  2834. end;
  2835. procedure TCustomSQLQuery.DoOnNewRecord;
  2836. begin
  2837. inherited;
  2838. if FSequence.ApplyEvent = saeOnNewRecord then
  2839. FSequence.Apply;
  2840. end;
  2841. procedure TCustomSQLQuery.DoBeforePost;
  2842. begin
  2843. if (State = dsInsert) and (FSequence.ApplyEvent = saeOnPost) then
  2844. FSequence.Apply;
  2845. inherited;
  2846. end;
  2847. function TCustomSQLQuery.PSGetUpdateException(E: Exception; Prev: EUpdateError): EUpdateError;
  2848. var
  2849. PrevErrorCode, ErrorCode: Integer;
  2850. begin
  2851. if Assigned(Prev) then
  2852. PrevErrorCode := Prev.ErrorCode
  2853. else
  2854. PrevErrorCode := 0;
  2855. if E is ESQLDatabaseError then
  2856. ErrorCode := ESQLDatabaseError(E).ErrorCode
  2857. else
  2858. ErrorCode := 0;
  2859. Result := EUpdateError.Create(SOnUpdateError, E.Message, ErrorCode, PrevErrorCode, E);
  2860. end;
  2861. function TCustomSQLQuery.PSGetTableName: string;
  2862. begin
  2863. Result := FTableName;
  2864. end;
  2865. { TSQLScript }
  2866. procedure TSQLScript.ExecuteStatement(SQLStatement: TStrings;
  2867. var StopExecution: Boolean);
  2868. begin
  2869. fquery.SQL.assign(SQLStatement);
  2870. fquery.ExecSQL;
  2871. end;
  2872. procedure TSQLScript.ExecuteDirective(Directive, Argument: String;
  2873. var StopExecution: Boolean);
  2874. begin
  2875. if assigned (FOnDirective) then
  2876. FOnDirective (Self, Directive, Argument, StopExecution);
  2877. end;
  2878. procedure TSQLScript.ExecuteCommit(CommitRetaining: boolean=true);
  2879. begin
  2880. if FTransaction is TSQLTransaction then
  2881. if CommitRetaining then
  2882. TSQLTransaction(FTransaction).CommitRetaining
  2883. else
  2884. begin
  2885. TSQLTransaction(FTransaction).Commit;
  2886. TSQLTransaction(FTransaction).StartTransaction;
  2887. end
  2888. else
  2889. begin
  2890. FTransaction.Active := false;
  2891. FTransaction.Active := true;
  2892. end;
  2893. end;
  2894. procedure TSQLScript.SetDatabase(Value: TDatabase);
  2895. begin
  2896. FDatabase := Value;
  2897. end;
  2898. procedure TSQLScript.SetTransaction(Value: TDBTransaction);
  2899. begin
  2900. FTransaction := Value;
  2901. end;
  2902. procedure TSQLScript.CheckDatabase;
  2903. begin
  2904. If (FDatabase=Nil) then
  2905. DatabaseError(SErrNoDatabaseAvailable,Self)
  2906. end;
  2907. function TSQLScript.CreateQuery: TCustomSQLQuery;
  2908. begin
  2909. Result := TCustomSQLQuery.Create(nil);
  2910. Result.ParamCheck := false; // Do not parse for parameters; breaks use of e.g. select bla into :bla in Firebird procedures
  2911. end;
  2912. constructor TSQLScript.Create(AOwner: TComponent);
  2913. begin
  2914. inherited Create(AOwner);
  2915. FQuery := CreateQuery;
  2916. end;
  2917. destructor TSQLScript.Destroy;
  2918. begin
  2919. FQuery.Free;
  2920. inherited Destroy;
  2921. end;
  2922. procedure TSQLScript.Execute;
  2923. begin
  2924. FQuery.DataBase := FDatabase;
  2925. FQuery.Transaction := FTransaction;
  2926. inherited Execute;
  2927. end;
  2928. procedure TSQLScript.ExecuteScript;
  2929. begin
  2930. Execute;
  2931. end;
  2932. { Connection definitions }
  2933. Var
  2934. ConnDefs : TStringList;
  2935. Procedure CheckDefs;
  2936. begin
  2937. If (ConnDefs=Nil) then
  2938. begin
  2939. ConnDefs:=TStringList.Create;
  2940. ConnDefs.Sorted:=True;
  2941. ConnDefs.Duplicates:=dupError;
  2942. end;
  2943. end;
  2944. Procedure DoneDefs;
  2945. Var
  2946. I : Integer;
  2947. begin
  2948. If Assigned(ConnDefs) then
  2949. begin
  2950. For I:=ConnDefs.Count-1 downto 0 do
  2951. begin
  2952. ConnDefs.Objects[i].Free;
  2953. ConnDefs.Delete(I);
  2954. end;
  2955. FreeAndNil(ConnDefs);
  2956. end;
  2957. end;
  2958. Function GetConnectionDef(ConnectorName : String) : TConnectionDef;
  2959. Var
  2960. I : Integer;
  2961. begin
  2962. CheckDefs;
  2963. I:=ConnDefs.IndexOf(ConnectorName);
  2964. If (I<>-1) then
  2965. Result:=TConnectionDef(ConnDefs.Objects[i])
  2966. else
  2967. Result:=Nil;
  2968. end;
  2969. procedure RegisterConnection(Def: TConnectionDefClass);
  2970. Var
  2971. I : Integer;
  2972. begin
  2973. CheckDefs;
  2974. I:=ConnDefs.IndexOf(Def.TypeName);
  2975. If (I=-1) then
  2976. ConnDefs.AddObject(Def.TypeName,Def.Create)
  2977. else
  2978. begin
  2979. ConnDefs.Objects[I].Free;
  2980. ConnDefs.Objects[I]:=Def.Create;
  2981. end;
  2982. end;
  2983. procedure UnRegisterConnection(Def: TConnectionDefClass);
  2984. begin
  2985. UnRegisterConnection(Def.TypeName);
  2986. end;
  2987. procedure UnRegisterConnection(ConnectionName: String);
  2988. Var
  2989. I : Integer;
  2990. begin
  2991. if (ConnDefs<>Nil) then
  2992. begin
  2993. I:=ConnDefs.IndexOf(ConnectionName);
  2994. If (I<>-1) then
  2995. begin
  2996. ConnDefs.Objects[I].Free;
  2997. ConnDefs.Delete(I);
  2998. end;
  2999. end;
  3000. end;
  3001. procedure GetConnectionList(List: TSTrings);
  3002. begin
  3003. CheckDefs;
  3004. List.Text:=ConnDefs.Text;
  3005. end;
  3006. { TSQLConnector }
  3007. procedure TSQLConnector.SetConnectorType(const AValue: String);
  3008. begin
  3009. if FConnectorType<>AValue then
  3010. begin
  3011. CheckDisconnected;
  3012. If Assigned(FProxy) then
  3013. FreeProxy;
  3014. FConnectorType:=AValue;
  3015. CreateProxy;
  3016. end;
  3017. end;
  3018. procedure TSQLConnector.SetTransaction(Value: TSQLTransaction);
  3019. begin
  3020. inherited SetTransaction(Value);
  3021. If Assigned(FProxy) and (FProxy.Transaction<>Value) then
  3022. FProxy.FTransaction:=Value;
  3023. end;
  3024. procedure TSQLConnector.DoInternalConnect;
  3025. Var
  3026. D : TConnectionDef;
  3027. begin
  3028. inherited DoInternalConnect;
  3029. CheckProxy;
  3030. FProxy.CharSet:=Self.CharSet;
  3031. FProxy.DatabaseName:=Self.DatabaseName;
  3032. FProxy.HostName:=Self.HostName;
  3033. FProxy.LogEvents:=Self.LogEvents;
  3034. FProxy.Password:=Self.Password;
  3035. FProxy.Role:=Self.Role;
  3036. FProxy.UserName:=Self.UserName;
  3037. FProxy.FTransaction:=Self.Transaction;
  3038. FProxy.LogEvents:=Self.LogEvents;
  3039. FProxy.OnLog:=Self.OnLog;
  3040. FProxy.Options:=Self.Options;
  3041. D:=GetConnectionDef(ConnectorType);
  3042. D.ApplyParams(Params,FProxy);
  3043. FProxy.Connected:=True;
  3044. end;
  3045. procedure TSQLConnector.DoInternalDisconnect;
  3046. begin
  3047. FProxy.Connected:=False;
  3048. inherited DoInternalDisconnect;
  3049. end;
  3050. procedure TSQLConnector.CheckProxy;
  3051. begin
  3052. If (FProxy=Nil) then
  3053. CreateProxy;
  3054. end;
  3055. procedure TSQLConnector.CreateProxy;
  3056. Var
  3057. D : TConnectionDef;
  3058. begin
  3059. D:=GetConnectionDef(ConnectorType);
  3060. If (D=Nil) then
  3061. DatabaseErrorFmt(SErrUnknownConnectorType,[ConnectorType],Self);
  3062. FProxy:=D.ConnectionClass.Create(Self);
  3063. FFieldNameQuoteChars := FProxy.FieldNameQuoteChars;
  3064. FConnOptions := FProxy.ConnOptions;
  3065. end;
  3066. procedure TSQLConnector.FreeProxy;
  3067. begin
  3068. FProxy.Connected:=False;
  3069. FreeAndNil(FProxy);
  3070. end;
  3071. function TSQLConnector.StrToStatementType(s: string): TStatementType;
  3072. begin
  3073. CheckProxy;
  3074. Result:=FProxy.StrToStatementType(s);
  3075. end;
  3076. function TSQLConnector.GetAsSQLText(Field: TField): string;
  3077. begin
  3078. CheckProxy;
  3079. Result:=FProxy.GetAsSQLText(Field);
  3080. end;
  3081. function TSQLConnector.GetAsSQLText(Param: TParam): string;
  3082. begin
  3083. CheckProxy;
  3084. Result:=FProxy.GetAsSQLText(Param);
  3085. end;
  3086. function TSQLConnector.GetHandle: pointer;
  3087. begin
  3088. CheckProxy;
  3089. Result:=FProxy.GetHandle;
  3090. end;
  3091. function TSQLConnector.AllocateCursorHandle: TSQLCursor;
  3092. begin
  3093. CheckProxy;
  3094. Result:=FProxy.AllocateCursorHandle;
  3095. end;
  3096. procedure TSQLConnector.DeAllocateCursorHandle(var cursor: TSQLCursor);
  3097. begin
  3098. CheckProxy;
  3099. FProxy.DeAllocateCursorHandle(cursor);
  3100. end;
  3101. function TSQLConnector.AllocateTransactionHandle: TSQLHandle;
  3102. begin
  3103. CheckProxy;
  3104. Result:=FProxy.AllocateTransactionHandle;
  3105. end;
  3106. procedure TSQLConnector.PrepareStatement(cursor: TSQLCursor;
  3107. ATransaction: TSQLTransaction; buf: string; AParams: TParams);
  3108. begin
  3109. CheckProxy;
  3110. FProxy.PrepareStatement(cursor, ATransaction, buf, AParams);
  3111. end;
  3112. procedure TSQLConnector.Execute(cursor: TSQLCursor;
  3113. atransaction: tSQLtransaction; AParams: TParams);
  3114. begin
  3115. CheckProxy;
  3116. FProxy.Execute(cursor, atransaction, AParams);
  3117. end;
  3118. function TSQLConnector.Fetch(cursor: TSQLCursor): boolean;
  3119. begin
  3120. CheckProxy;
  3121. Result:=FProxy.Fetch(cursor);
  3122. end;
  3123. procedure TSQLConnector.AddFieldDefs(cursor: TSQLCursor; FieldDefs: TfieldDefs
  3124. );
  3125. begin
  3126. CheckProxy;
  3127. FProxy.AddFieldDefs(cursor, FieldDefs);
  3128. end;
  3129. procedure TSQLConnector.UnPrepareStatement(cursor: TSQLCursor);
  3130. begin
  3131. CheckProxy;
  3132. FProxy.UnPrepareStatement(cursor);
  3133. end;
  3134. procedure TSQLConnector.FreeFldBuffers(cursor: TSQLCursor);
  3135. begin
  3136. CheckProxy;
  3137. FProxy.FreeFldBuffers(cursor);
  3138. end;
  3139. function TSQLConnector.GetNextValueSQL(const SequenceName: string; IncrementBy: Integer): string;
  3140. begin
  3141. Result:=Proxy.GetNextValueSQL(SequenceName, IncrementBy);
  3142. end;
  3143. function TSQLConnector.LoadField(cursor: TSQLCursor; FieldDef: TFieldDef;
  3144. buffer: pointer; out CreateBlob: boolean): boolean;
  3145. begin
  3146. CheckProxy;
  3147. Result:=FProxy.LoadField(cursor, FieldDef, buffer, CreateBlob);
  3148. end;
  3149. procedure TSQLConnector.LoadBlobIntoBuffer(FieldDef: TFieldDef;
  3150. ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction: TSQLTransaction);
  3151. begin
  3152. CheckProxy;
  3153. FProxy.LoadBlobIntoBuffer(FieldDef, ABlobBuf, cursor, ATransaction);
  3154. end;
  3155. function TSQLConnector.RowsAffected(cursor: TSQLCursor): TRowsCount;
  3156. begin
  3157. CheckProxy;
  3158. Result := FProxy.RowsAffected(cursor);
  3159. end;
  3160. function TSQLConnector.GetTransactionHandle(trans: TSQLHandle): pointer;
  3161. begin
  3162. CheckProxy;
  3163. Result:=FProxy.GetTransactionHandle(trans);
  3164. end;
  3165. function TSQLConnector.Commit(trans: TSQLHandle): boolean;
  3166. begin
  3167. CheckProxy;
  3168. Result:=FProxy.Commit(trans);
  3169. end;
  3170. function TSQLConnector.RollBack(trans: TSQLHandle): boolean;
  3171. begin
  3172. CheckProxy;
  3173. Result:=FProxy.RollBack(trans);
  3174. end;
  3175. function TSQLConnector.StartDBTransaction(trans: TSQLHandle; aParams: string): boolean;
  3176. begin
  3177. CheckProxy;
  3178. Result:=FProxy.StartDBTransaction(trans, aParams);
  3179. end;
  3180. procedure TSQLConnector.CommitRetaining(trans: TSQLHandle);
  3181. begin
  3182. CheckProxy;
  3183. FProxy.CommitRetaining(trans);
  3184. end;
  3185. procedure TSQLConnector.RollBackRetaining(trans: TSQLHandle);
  3186. begin
  3187. CheckProxy;
  3188. FProxy.RollBackRetaining(trans);
  3189. end;
  3190. procedure TSQLConnector.UpdateIndexDefs(IndexDefs: TIndexDefs;
  3191. TableName: string);
  3192. begin
  3193. CheckProxy;
  3194. FProxy.UpdateIndexDefs(IndexDefs, TableName);
  3195. end;
  3196. function TSQLConnector.GetSchemaInfoSQL(SchemaType: TSchemaType;
  3197. SchemaObjectName, SchemaPattern: string): string;
  3198. begin
  3199. CheckProxy;
  3200. Result:=FProxy.GetSchemaInfoSQL(SchemaType, SchemaObjectName, SchemaPattern);
  3201. end;
  3202. { TConnectionDef }
  3203. class function TConnectionDef.TypeName: String;
  3204. begin
  3205. Result:='';
  3206. end;
  3207. class function TConnectionDef.ConnectionClass: TSQLConnectionClass;
  3208. begin
  3209. Result:=Nil;
  3210. end;
  3211. class function TConnectionDef.Description: String;
  3212. begin
  3213. Result:='';
  3214. end;
  3215. class function TConnectionDef.DefaultLibraryName: String;
  3216. begin
  3217. Result:='';
  3218. end;
  3219. class function TConnectionDef.LoadFunction: TLibraryLoadFunction;
  3220. begin
  3221. Result:=Nil;
  3222. end;
  3223. class function TConnectionDef.UnLoadFunction: TLibraryUnLoadFunction;
  3224. begin
  3225. Result:=Nil;
  3226. end;
  3227. class function TConnectionDef.LoadedLibraryName: string;
  3228. begin
  3229. Result:='';
  3230. end;
  3231. procedure TConnectionDef.ApplyParams(Params: TStrings;
  3232. AConnection: TSQLConnection);
  3233. begin
  3234. AConnection.Params.Assign(Params);
  3235. end;
  3236. { TServerIndexDefs }
  3237. constructor TServerIndexDefs.create(ADataset: TDataset);
  3238. begin
  3239. if not (ADataset is TCustomSQLQuery) then
  3240. DatabaseErrorFmt(SErrNotASQLQuery,[ADataset.Name]);
  3241. inherited create(ADataset);
  3242. end;
  3243. procedure TServerIndexDefs.Update;
  3244. begin
  3245. if (not updated) and assigned(Dataset) then
  3246. begin
  3247. TCustomSQLQuery(Dataset).UpdateServerIndexDefs;
  3248. updated := True;
  3249. end;
  3250. end;
  3251. Initialization
  3252. Finalization
  3253. DoneDefs;
  3254. end.