sqldb.pp 114 KB

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