sqldb.pp 117 KB

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