sqldb.pp 119 KB

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