Rev 7 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 7 | Rev 8 | ||
---|---|---|---|
1 | unit AdoConnHelper; |
1 | unit AdoConnHelper; |
2 | 2 | ||
3 | (* |
3 | (* |
4 | * Class helper for TAdoConnection |
4 | * Class helper for TAdoConnection |
5 | * by Daniel Marschall, ViaThinkSoft <www.viathinksoft.com> |
5 | * by Daniel Marschall, ViaThinkSoft <www.viathinksoft.com> |
6 | * Revision: 28 Aug 2018 |
6 | * Revision: 14 June 2021 |
7 | *) |
7 | *) |
8 | 8 | ||
9 | interface |
9 | interface |
10 | 10 | ||
11 | uses |
11 | uses |
12 | DB, ADODB, Variants, Classes, SysUtils; |
12 | DB, ADODB, Variants, Classes, SysUtils; |
13 | 13 | ||
14 | type |
14 | type |
15 | TAdoConnectionHelper = class helper for TADOConnection |
15 | TAdoConnectionHelper = class helper for TADOConnection |
16 | private |
16 | private |
17 | function GetConnectionID: TGUID; |
17 | function GetConnectionID: TGUID; |
18 | public |
18 | public |
19 | // Attention: Some of the functions here (e.g. ConnectionID) require SQL Server |
19 | // Attention: Some of the functions here (e.g. ConnectionID) require SQL Server |
20 | function GetTable(SQL: string; ATimeout: integer=-1): TADODataSet; |
20 | function GetTable(SQL: string; ATimeout: integer=-1): TADODataSet; |
21 | function GetScalar(SQL: string; ATimeout: integer=-1): Variant; |
21 | function GetScalar(SQL: string; ATimeout: integer=-1): Variant; |
22 | procedure ExecSQL(SQL: string; ATimeout: integer=-1); |
22 | procedure ExecSQL(SQL: string; ATimeout: integer=-1); |
23 | procedure ExecSQLList(List: TStrings; ATimeout: integer=-1); |
23 | procedure ExecSQLList(List: TStrings; ATimeout: integer=-1); |
24 | procedure Connect(AConnectionString: string; ATimeout: integer=-1); |
24 | procedure Connect(AConnectionString: string; ATimeout: integer=-1); |
25 | procedure Disconnect; |
25 | procedure Disconnect; |
26 | class function SQLStringEscape(str: string): string; static; |
26 | class function SQLStringEscape(str: string): string; static; |
27 | class function SQLObjectNameEscape(str: string): string; static; |
27 | class function SQLObjectNameEscape(str: string): string; static; |
28 | procedure GetPrimaryKeyNames(TableName: string; outsl: TStrings); |
28 | procedure GetPrimaryKeyNames(TableName: string; outsl: TStrings); |
29 | property ConnectionID: TGUID read GetConnectionID; |
29 | property ConnectionID: TGUID read GetConnectionID; |
30 | function InsertAndReturnID(query: string): integer; |
30 | function InsertAndReturnID(query: string): integer; |
31 | procedure DropTable(aTableName: string); |
31 | procedure DropTable(aTableName: string); |
32 | function FieldCount(aTableName: string): integer; |
32 | function FieldCount(aTableName: string): integer; |
33 | function IndexCount(aTableName: string): integer; |
33 | function IndexCount(aTableName: string): integer; |
34 | function TableExist(aTableName: string): boolean; |
34 | function TableExist(aTableName: string): boolean; |
35 | function ViewExist(aViewName: string): boolean; |
35 | function ViewExist(aViewName: string): boolean; |
36 | function ColumnExists(aTableName, aColumnName: string): boolean; |
36 | function ColumnExists(aTableName, aColumnName: string): boolean; |
37 | procedure GetTableNames(List: TStrings; SystemTables: Boolean=false); |
37 | procedure GetTableNames(List: TStrings; SystemTables: Boolean=false); |
38 | //property TransactionLevel: integer read FTransactionLevel; |
38 | //property TransactionLevel: integer read FTransactionLevel; |
39 | end; |
39 | end; |
40 | 40 | ||
41 | implementation |
41 | implementation |
42 | 42 | ||
43 | { TAdoConnectionHelper } |
43 | { TAdoConnectionHelper } |
44 | 44 | ||
45 | function TAdoConnectionHelper.GetConnectionID: TGUID; |
45 | function TAdoConnectionHelper.GetConnectionID: TGUID; |
46 | var |
46 | var |
47 | s : string; |
47 | s : string; |
48 | begin |
48 | begin |
49 | s := GetScalar('select connection_id from sys.dm_exec_connections ec ' + |
49 | s := GetScalar('select connection_id from sys.dm_exec_connections ec ' + |
50 | 'left join sys.dm_exec_sessions se on ec.session_id = se.session_id ' + |
50 | 'left join sys.dm_exec_sessions se on ec.session_id = se.session_id ' + |
51 | 'where se.session_id = @@SPID'); |
51 | 'where se.session_id = @@SPID'); |
52 | result := StringToGUID(s); |
52 | result := StringToGUID(s); |
53 | end; |
53 | end; |
54 | 54 | ||
55 | procedure TAdoConnectionHelper.GetPrimaryKeyNames(TableName: string; outsl: TStrings); |
55 | procedure TAdoConnectionHelper.GetPrimaryKeyNames(TableName: string; outsl: TStrings); |
56 | var |
56 | var |
57 | ds: TADODataSet; |
57 | ds: TADODataSet; |
58 | begin |
58 | begin |
59 | ds := TADODataSet.Create(nil); |
59 | ds := TADODataSet.Create(nil); |
60 | try |
60 | try |
61 | OpenSchema(siPrimaryKeys, Unassigned, EmptyParam, ds); |
61 | OpenSchema(siPrimaryKeys, Unassigned, EmptyParam, ds); |
62 | while not ds.Eof do |
62 | while not ds.Eof do |
63 | begin |
63 | begin |
64 | if ds.FieldByName('TABLE_NAME').AsString = TableName then |
64 | if ds.FieldByName('TABLE_NAME').AsString = TableName then |
65 | begin |
65 | begin |
66 | outsl.Add(ds.FieldByName('COLUMN_NAME').AsString); |
66 | outsl.Add(ds.FieldByName('COLUMN_NAME').AsString); |
67 | end; |
67 | end; |
68 | ds.Next; |
68 | ds.Next; |
69 | end; |
69 | end; |
70 | ds.Close; |
70 | ds.Close; |
71 | finally |
71 | finally |
72 | ds.Free; |
72 | ds.Free; |
73 | end; |
73 | end; |
74 | end; |
74 | end; |
75 | 75 | ||
76 | function TAdoConnectionHelper.GetScalar(SQL: string; ATimeout: integer=-1): Variant; |
76 | function TAdoConnectionHelper.GetScalar(SQL: string; ATimeout: integer=-1): Variant; |
77 | var |
77 | var |
78 | ds: TADODataSet; |
78 | ds: TADODataSet; |
79 | begin |
79 | begin |
80 | ds := GetTable(SQL, ATimeout); |
80 | ds := GetTable(SQL, ATimeout); |
81 | result := ds.Fields[0].AsVariant; |
81 | result := ds.Fields[0].AsVariant; |
82 | ds.Free; |
82 | ds.Free; |
83 | end; |
83 | end; |
84 | 84 | ||
85 | function TAdoConnectionHelper.GetTable(SQL: string; ATimeout: integer=-1): TADODataSet; |
85 | function TAdoConnectionHelper.GetTable(SQL: string; ATimeout: integer=-1): TADODataSet; |
86 | begin |
86 | begin |
87 | result := TADODataSet.Create(nil); |
87 | result := TADODataSet.Create(nil); |
88 | result.Connection := Self; |
88 | result.Connection := Self; |
89 | result.EnableBCD := false; |
89 | result.EnableBCD := false; |
90 | result.ParamCheck := false; |
90 | result.ParamCheck := false; |
91 | result.CommandType := cmdText; |
91 | result.CommandType := cmdText; |
92 | result.CommandText := SQL; |
92 | result.CommandText := SQL; |
93 | result.DisableControls; |
93 | result.DisableControls; |
- | 94 | if ATimeout <> -1 then |
|
94 | if ATimeout <> -1 then result.CommandTimeout := ATimeout; |
95 | result.CommandTimeout := ATimeout |
- | 96 | else |
|
- | 97 | result.CommandTimeout := self.CommandTimeout; |
|
95 | result.Active := true; |
98 | result.Active := true; |
96 | end; |
99 | end; |
97 | 100 | ||
98 | function TAdoConnectionHelper.ColumnExists(aTableName, aColumnName: string): boolean; |
101 | function TAdoConnectionHelper.ColumnExists(aTableName, aColumnName: string): boolean; |
99 | begin |
102 | begin |
100 | result := GetScalar('select count (*) from sys.columns where Name = '+SQLStringEscape(aColumnName)+' and Object_ID = Object_ID('+SQLStringEscape(aTableName)+')') > 0; |
103 | result := GetScalar('select count (*) from sys.columns where Name = '+SQLStringEscape(aColumnName)+' and Object_ID = Object_ID('+SQLStringEscape(aTableName)+')') > 0; |
101 | end; |
104 | end; |
102 | 105 | ||
103 | procedure TAdoConnectionHelper.GetTableNames(List: TStrings; |
106 | procedure TAdoConnectionHelper.GetTableNames(List: TStrings; |
104 | SystemTables: Boolean); |
107 | SystemTables: Boolean); |
105 | begin |
108 | begin |
106 | 109 | ||
107 | end; |
110 | end; |
108 | 111 | ||
109 | function TAdoConnectionHelper.IndexCount(aTableName: string): integer; |
112 | function TAdoConnectionHelper.IndexCount(aTableName: string): integer; |
110 | begin |
113 | begin |
111 | result := GetScalar('select max (ik.indid) from sysindexkeys ik left join sysindexes ind on ind.id = ik.id and ind.indid = ik.indid where ik.id = (select id from sysobjects ' + |
114 | result := GetScalar('select max (ik.indid) from sysindexkeys ik left join sysindexes ind on ind.id = ik.id and ind.indid = ik.indid where ik.id = (select id from sysobjects ' + |
112 | 'where name = ''' + aTableName + ''') and ind.status < 10000000'); |
115 | 'where name = ''' + aTableName + ''') and ind.status < 10000000'); |
113 | end; |
116 | end; |
114 | 117 | ||
115 | function TAdoConnectionHelper.InsertAndReturnID(query: string): integer; |
118 | function TAdoConnectionHelper.InsertAndReturnID(query: string): integer; |
116 | resourcestring |
119 | resourcestring |
117 | LNG_NO_AUTOINC = 'Cannot find AutoIncrement value'; |
120 | LNG_NO_AUTOINC = 'Cannot find AutoIncrement value'; |
118 | var |
121 | var |
119 | q1: TADODataSet; |
122 | q1: TADODataSet; |
120 | begin |
123 | begin |
121 | BeginTrans; |
124 | BeginTrans; |
122 | try |
125 | try |
123 | ExecSql(query); // Execute(query); |
126 | ExecSql(query); // Execute(query); |
124 | 127 | ||
125 | // Hinweis: Das geht nur lokal, nicht über linked servers |
128 | // Hinweis: Das geht nur lokal, nicht über linked servers |
126 | // TODO: Man sollte lieber SCOPE_IDENTITY() verwenden |
129 | // TODO: Man sollte lieber SCOPE_IDENTITY() verwenden |
127 | q1 := GetTable('select @@IDENTITY as INSERT_ID;'); |
130 | q1 := GetTable('select @@IDENTITY as INSERT_ID;'); |
128 | try |
131 | try |
129 | if (q1.RecordCount = 0) or (q1.{FieldByName('INSERT_ID')}Fields[0].AsInteger = 0) then |
132 | if (q1.RecordCount = 0) or (q1.{FieldByName('INSERT_ID')}Fields[0].AsInteger = 0) then |
130 | begin |
133 | begin |
131 | //result := -1; |
134 | //result := -1; |
132 | raise EADOError.Create(LNG_NO_AUTOINC); |
135 | raise EADOError.Create(LNG_NO_AUTOINC); |
133 | end; |
136 | end; |
134 | 137 | ||
135 | result := q1.{FieldByName('INSERT_ID')}Fields[0].AsInteger; |
138 | result := q1.{FieldByName('INSERT_ID')}Fields[0].AsInteger; |
136 | finally |
139 | finally |
137 | FreeAndNil(q1); |
140 | FreeAndNil(q1); |
138 | end; |
141 | end; |
139 | finally |
142 | finally |
140 | CommitTrans; |
143 | CommitTrans; |
141 | end; |
144 | end; |
142 | end; |
145 | end; |
143 | 146 | ||
144 | procedure TAdoConnectionHelper.Connect(AConnectionString: string; ATimeout: integer=-1); |
147 | procedure TAdoConnectionHelper.Connect(AConnectionString: string; ATimeout: integer=-1); |
145 | begin |
148 | begin |
146 | Disconnect; |
149 | Disconnect; |
147 | ConnectionString := AConnectionString; |
150 | ConnectionString := AConnectionString; |
148 | if ATimeout <> -1 then ConnectionTimeout := ATimeout; |
151 | if ATimeout <> -1 then ConnectionTimeout := ATimeout; |
149 | Connected := true; |
152 | Connected := true; |
150 | end; |
153 | end; |
151 | 154 | ||
152 | procedure TAdoConnectionHelper.Disconnect; |
155 | procedure TAdoConnectionHelper.Disconnect; |
153 | begin |
156 | begin |
154 | Connected := false; |
157 | Connected := false; |
155 | end; |
158 | end; |
156 | 159 | ||
157 | procedure TAdoConnectionHelper.DropTable(aTableName: string); |
160 | procedure TAdoConnectionHelper.DropTable(aTableName: string); |
158 | begin |
161 | begin |
159 | if ViewExist(aTableName) then |
162 | if ViewExist(aTableName) then |
160 | begin |
163 | begin |
161 | ExecSql('drop view ' + SQLObjectNameEscape(aTableName)); |
164 | ExecSql('drop view ' + SQLObjectNameEscape(aTableName)); |
162 | end; |
165 | end; |
163 | if TableExist(aTableName) then |
166 | if TableExist(aTableName) then |
164 | begin |
167 | begin |
165 | ExecSql('drop table ' + SQLObjectNameEscape(aTableName)); |
168 | ExecSql('drop table ' + SQLObjectNameEscape(aTableName)); |
166 | end; |
169 | end; |
167 | end; |
170 | end; |
168 | 171 | ||
169 | procedure TAdoConnectionHelper.ExecSQL(SQL: string; ATimeout: integer); |
172 | procedure TAdoConnectionHelper.ExecSQL(SQL: string; ATimeout: integer); |
170 | var |
173 | var |
171 | cmd: TADOCommand; |
174 | cmd: TADOCommand; |
172 | begin |
175 | begin |
173 | cmd := TADOCommand.Create(nil); |
176 | cmd := TADOCommand.Create(nil); |
174 | try |
177 | try |
175 | cmd.Connection := Self; |
178 | cmd.Connection := Self; |
176 | cmd.ParamCheck := false; |
179 | cmd.ParamCheck := false; |
177 | cmd.CommandType := cmdText; |
180 | cmd.CommandType := cmdText; |
178 | cmd.CommandText := SQL; |
181 | cmd.CommandText := SQL; |
- | 182 | if ATimeOut <> -1 then |
|
179 | if ATimeOut <> -1 then cmd.CommandTimeout := ATimeout; |
183 | cmd.CommandTimeout := ATimeout |
- | 184 | else |
|
- | 185 | cmd.CommandTimeout := self.CommandTimeout; |
|
180 | cmd.Execute; |
186 | cmd.Execute; |
181 | finally |
187 | finally |
182 | cmd.Free; |
188 | cmd.Free; |
183 | end; |
189 | end; |
184 | end; |
190 | end; |
185 | 191 | ||
186 | procedure TAdoConnectionHelper.ExecSQLList(List: TStrings; ATimeout: integer); |
192 | procedure TAdoConnectionHelper.ExecSQLList(List: TStrings; ATimeout: integer); |
187 | var |
193 | var |
188 | s: string; |
194 | s: string; |
189 | begin |
195 | begin |
190 | for s in List do |
196 | for s in List do |
191 | begin |
197 | begin |
192 | ExecSQL(s); |
198 | ExecSQL(s, ATimeout); |
193 | end; |
199 | end; |
194 | end; |
200 | end; |
195 | 201 | ||
196 | function TAdoConnectionHelper.FieldCount(aTableName: string): integer; |
202 | function TAdoConnectionHelper.FieldCount(aTableName: string): integer; |
197 | begin |
203 | begin |
198 | result := GetScalar('select count (*) from syscolumns where id = (select id from sysobjects where name = ''' + aTableName + ''') '); |
204 | result := GetScalar('select count (*) from syscolumns where id = (select id from sysobjects where name = ''' + aTableName + ''') '); |
199 | end; |
205 | end; |
200 | 206 | ||
201 | class function TAdoConnectionHelper.SQLStringEscape(str: string): string; |
207 | class function TAdoConnectionHelper.SQLStringEscape(str: string): string; |
202 | begin |
208 | begin |
203 | result := str; |
209 | result := str; |
204 | 210 | ||
205 | // Escape SQL-Argument |
211 | // Escape SQL-Argument |
206 | (* |
212 | (* |
207 | result := StringReplace(result, '\', '\\', [rfReplaceAll]); |
213 | result := StringReplace(result, '\', '\\', [rfReplaceAll]); |
208 | result := StringReplace(result, '_', '\_', [rfReplaceAll]); |
214 | result := StringReplace(result, '_', '\_', [rfReplaceAll]); |
209 | result := StringReplace(result, '%', '\%', [rfReplaceAll]); |
215 | result := StringReplace(result, '%', '\%', [rfReplaceAll]); |
210 | result := StringReplace(result, '[', '\[', [rfReplaceAll]); |
216 | result := StringReplace(result, '[', '\[', [rfReplaceAll]); |
211 | result := StringReplace(result, '''', '\''', [rfReplaceAll]); |
217 | result := StringReplace(result, '''', '\''', [rfReplaceAll]); |
212 | *) |
218 | *) |
213 | 219 | ||
214 | // DM 29.02.2016 Irgendwie versteh ich das nicht... |
220 | // DM 29.02.2016 Irgendwie versteh ich das nicht... |
215 | // 'xxx\'xxx' ist erlaubt, aber 'xxx\'xxx\'xxx' nicht |
221 | // 'xxx\'xxx' ist erlaubt, aber 'xxx\'xxx\'xxx' nicht |
216 | // aber 'xxx''xxx''xxx' geht. |
222 | // aber 'xxx''xxx''xxx' geht. |
217 | result := StringReplace(result, '''', '''''', [rfReplaceAll]); |
223 | result := StringReplace(result, '''', '''''', [rfReplaceAll]); |
218 | 224 | ||
219 | // Verhindern, dass SQL Server denkt, es sei ein Parameterobjekt |
225 | // Verhindern, dass SQL Server denkt, es sei ein Parameterobjekt |
220 | // Brauchen wir nur, wenn die abfrage ParamCheck=true hat. |
226 | // Brauchen wir nur, wenn die abfrage ParamCheck=true hat. |
221 | // Wir haben aber in hl_Datenbank.pas das immer auf false. |
227 | // Wir haben aber in hl_Datenbank.pas das immer auf false. |
222 | // result := StringReplace(result, ':', '::', [rfReplaceAll]); |
228 | // result := StringReplace(result, ':', '::', [rfReplaceAll]); |
223 | 229 | ||
224 | {$IFDEF UNICODE} |
230 | {$IFDEF UNICODE} |
225 | result := 'N''' + result + ''''; |
231 | result := 'N''' + result + ''''; |
226 | {$ELSE} |
232 | {$ELSE} |
227 | result := '''' + result + ''''; |
233 | result := '''' + result + ''''; |
228 | {$ENDIF} |
234 | {$ENDIF} |
229 | end; |
235 | end; |
230 | 236 | ||
231 | function TAdoConnectionHelper.TableExist(aTableName: string): boolean; |
237 | function TAdoConnectionHelper.TableExist(aTableName: string): boolean; |
232 | begin |
238 | begin |
233 | if Copy(aTableName, 1, 1) = '#' then |
239 | if Copy(aTableName, 1, 1) = '#' then |
234 | begin |
240 | begin |
235 | // TempTable |
241 | // TempTable |
236 | result := GetScalar('select case when OBJECT_ID(''tempdb..'+aTableName+''') is not null then ''1'' else ''0'' end') > 0; |
242 | result := GetScalar('select case when OBJECT_ID(''tempdb..'+aTableName+''') is not null then ''1'' else ''0'' end') > 0; |
237 | end |
243 | end |
238 | else |
244 | else |
239 | begin |
245 | begin |
240 | // Physikalische Tabelle (in Schema dbo) |
246 | // Physikalische Tabelle (in Schema dbo) |
241 | // result := GetScalar('select count (*) from sysobjects where name = ' + aTableName.toSQLString) > 0; |
247 | // result := GetScalar('select count (*) from sysobjects where name = ' + aTableName.toSQLString) > 0; |
242 | result := GetScalar('SELECT count(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_CATALOG = N'''+DefaultDatabase+''' AND TABLE_SCHEMA = N''dbo'' AND TABLE_NAME = N'''+aTableName+'''') > 0; |
248 | result := GetScalar('SELECT count(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_CATALOG = N'''+DefaultDatabase+''' AND TABLE_SCHEMA = N''dbo'' AND TABLE_NAME = N'''+aTableName+'''') > 0; |
243 | end; |
249 | end; |
244 | end; |
250 | end; |
245 | 251 | ||
246 | function TAdoConnectionHelper.ViewExist(aViewName: string): boolean; |
252 | function TAdoConnectionHelper.ViewExist(aViewName: string): boolean; |
247 | begin |
253 | begin |
248 | result := GetScalar('select count(*) FROM sys.views where name = '+SQLStringEscape(aViewName)) > 0; |
254 | result := GetScalar('select count(*) FROM sys.views where name = '+SQLStringEscape(aViewName)) > 0; |
249 | end; |
255 | end; |
250 | 256 | ||
251 | class function TAdoConnectionHelper.SQLObjectNameEscape(str: string): string; |
257 | class function TAdoConnectionHelper.SQLObjectNameEscape(str: string): string; |
252 | begin |
258 | begin |
253 | result := '[dbo].[' + str + ']'; |
259 | result := '[dbo].[' + str + ']'; |
254 | end; |
260 | end; |
255 | 261 | ||
256 | end. |
262 | end. |
257 | 263 |