sqldb.pp 116 KB

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