1 {*********************************************************}
3 { Zeos Database Objects }
4 { Database Connectivity Functions }
6 { Originally written by Sergey Seroukhov }
8 {*********************************************************}
10 {@********************************************************}
11 { Copyright (c) 1999-2012 Zeos Development Group }
13 { License Agreement: }
15 { This library is distributed in the hope that it will be }
16 { useful, but WITHOUT ANY WARRANTY; without even the }
17 { implied warranty of MERCHANTABILITY or FITNESS FOR }
18 { A PARTICULAR PURPOSE. See the GNU Lesser General }
19 { Public License for more details. }
21 { The source code of the ZEOS Libraries and packages are }
22 { distributed under the Library GNU General Public }
23 { License (see the file COPYING / COPYING.ZEOS) }
24 { with the following modification: }
25 { As a special exception, the copyright holders of this }
26 { library give you permission to link this library with }
27 { independent modules to produce an executable, }
28 { regardless of the license terms of these independent }
29 { modules, and to copy and distribute the resulting }
30 { executable under terms of your choice, provided that }
31 { you also meet, for each linked independent module, }
32 { the terms and conditions of the license of that module. }
33 { An independent module is a module which is not derived }
34 { from or based on this library. If you modify this }
35 { library, you may extend this exception to your version }
36 { of the library, but you are not obligated to do so. }
37 { If you do not wish to do so, delete this exception }
38 { statement from your version. }
41 { The project web site is located on: }
42 { http://zeos.firmos.at (FORUM) }
43 { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)}
44 { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) }
46 { http://www.sourceforge.net/projects/zeoslib. }
49 { Zeos Development Group. }
50 {********************************************************@}
59 Types, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, Contnrs,
60 ZCompatibility, ZDbcIntfs, ZDbcResultSetMetadata;
63 Resolves a connection protocol and raises an exception with protocol
65 @param Url an initial database URL.
66 @param SuupportedProtocols a driver's supported subprotocols.
68 function ResolveConnectionProtocol(Url: string;
69 SupportedProtocols: TStringDynArray): string;
72 Resolves a database URL and fills the database connection parameters.
73 @param Url an initial database URL.
74 @param Info an initial info parameters.
75 @param HostName a name of the database host.
76 @param Port a port number.
77 @param Database a database name.
78 @param UserName a name of the database user.
79 @param Password a user's password.
80 @param ResutlInfo a result info parameters.
82 procedure ResolveDatabaseUrl(const Url: string; Info: TStrings;
83 var HostName: string; var Port: Integer; var Database: string;
84 var UserName: string; var Password: string; ResultInfo: TStrings);
87 Checks is the convertion from one type to another type allowed.
88 @param InitialType an initial data type.
89 @param ResultType a result data type.
90 @return <code>True</code> if convertion is allowed
91 or <code>False</code> otherwise.
93 function CheckConvertion(InitialType: TZSQLType; ResultType: TZSQLType): Boolean;
96 Defines a name of the column type.
97 @param ColumnType a type of the column.
98 @return a name of the specified type.
100 function DefineColumnTypeName(ColumnType: TZSQLType): string;
103 Raises a copy of the given exception.
104 @param E an exception to be raised.
106 procedure RaiseSQLException(E: Exception);
109 Copies column information objects from one object list to another one.
110 @param FromList the source object list.
111 @param ToList the destination object list.
113 procedure CopyColumnsInfo(FromList: TObjectList; ToList: TObjectList);
116 Defines a statement specific parameter.
117 @param Statement a statement interface reference.
118 @param ParamName a name of the parameter.
119 @param Default a parameter default value.
120 @return a parameter value or default if nothing was found.
122 function DefineStatementParameter(Statement: IZStatement; const ParamName: string;
123 const Default: string): string;
126 ToLikeString returns the given string or if the string is empty it returns '%'
127 @param Value the string
128 @return given Value or '%'
130 function ToLikeString(const Value: string): string;
133 GetSQLHexString returns a valid x'..' database understandable String from
135 @param Value the ansistring-pointer to the binary data
136 @param Len then length of the binary Data
137 @param ODBC a boolean if output result should be with a starting 0x...
138 @returns a valid hex formated unicode-safe string
140 function GetSQLHexWideString(Value: PAnsiChar; Len: Integer; ODBC: Boolean = False): ZWideString;
141 function GetSQLHexAnsiString(Value: PAnsiChar; Len: Integer; ODBC: Boolean = False): RawByteString;
142 function GetSQLHexString(Value: PAnsiChar; Len: Integer; ODBC: Boolean = False): String;
145 Returns a FieldSize in Bytes dependend to the FieldType and CharWidth
146 @param <code>TZSQLType</code> the Zeos FieldType
147 @param <code>Integer</code> the Current given FieldLength
148 @param <code>Integer</code> the Current CountOfByte/Char
149 @param <code>Boolean</code> does the Driver returns the FullSizeInBytes
150 @returns <code>Integer</code> the count of AnsiChars for Field.Size * SizeOf(Char)
152 function GetFieldSize(const SQLType: TZSQLType;ConSettings: PZConSettings;
153 const Precision, CharWidth: Integer; DisplaySize: PInteger = nil;
154 SizeInBytes: Boolean = False): Integer;
156 function WideStringStream(const AString: WideString): TStream;
160 uses ZMessages, ZSysUtils, ZEncoding;
163 Resolves a connection protocol and raises an exception with protocol
165 @param Url an initial database URL.
166 @param SupportedProtocols a driver's supported subprotocols.
168 function ResolveConnectionProtocol(Url: string;
169 SupportedProtocols: TStringDynArray): string;
177 Index := FirstDelimiter(':', Url);
179 Protocol := Copy(Url, Index + 1, Length(Url) - Index)
182 Index := FirstDelimiter(':', Protocol);
184 Protocol := Copy(Protocol, 1, Index - 1)
188 if Protocol = '' then
189 raise EZSQLException.Create(Format(SIncorrectConnectionURL, [Url]));
191 for I := Low(SupportedProtocols) to High(SupportedProtocols) do
193 if SupportedProtocols[I] = Protocol then
201 raise EZSQLException.Create(Format(SUnsupportedProtocol, [Protocol]));
205 Resolves a database URL and fills the database connection parameters.
206 @param Url an initial database URL.
207 @param Info an initial info parameters.
208 @param HostName a name of the database host.
209 @param Port a port number.
210 @param Database a database name.
211 @param UserName a name of the database user.
212 @param Password a user's password.
213 @param ResutlInfo a result info parameters.
215 procedure ResolveDatabaseUrl(const Url: string; Info: TStrings;
216 var HostName: string; var Port: Integer; var Database: string;
217 var UserName: string; var Password: string; ResultInfo: TStrings);
221 { assign URL first -> define all out out params }
222 {A correct builded URL exports all these Params if they are expected!}
223 DriverManager.ResolveDatabaseUrl(URL, HostName, Port, DataBase, UserName, Password, ResultInfo);
225 { Retrieves non special-escaped-parameters }
227 while FirstDelimiter('?', Temp) > 0 do //Get all aditional Parameters
228 Temp := Copy(Temp, FirstDelimiter('?', Temp)+1, Length(Temp));
229 PutSplitString(ResultInfo, Temp, ';'); //overrides all Strings
230 ResultInfo.Text := StringReplace(ResultInfo.Text, #9, ';', [rfReplaceAll]); //unescape the #9 char
232 if Assigned(Info) then //isn't that strange? (Shouldn't we pick out double-values?)
233 Resultinfo.AddStrings(Info);//All possible PWD/Password and UID/UserName are aviable now, but for what? And the can also be doubled!
235 { Redefines user name if not avialble in the URL}
236 if UserName = '' then //Priority 1: URL.UserName
238 UserName := ResultInfo.Values['UID']; //Priority 2: Info-UID
239 if UserName = '' then
240 UserName := ResultInfo.Values['username']; //Priority 3: Info-username
243 { Redefines user password if not avialble in the URL }
244 if Password = '' then //Priority 1: URL.Password
246 Password := ResultInfo.Values['PWD']; //Priority 2: Info-PWD
247 if Password = '' then
248 Password := ResultInfo.Values['password']; //Priority 3: Info-password
253 Checks is the convertion from one type to another type allowed.
254 @param InitialType an initial data type.
255 @param ResultType a result data type.
256 @return <code>True</code> if convertion is allowed
257 or <code>False</code> otherwise.
259 function CheckConvertion(InitialType: TZSQLType; ResultType: TZSQLType): Boolean;
262 stBoolean, stByte, stShort, stInteger,
263 stLong, stFloat, stDouble, stBigDecimal:
264 Result := InitialType in [stBoolean, stByte, stShort, stInteger,
265 stLong, stFloat, stDouble, stBigDecimal, stString, stUnicodeString];
266 stString, stUnicodeString:
269 Result := InitialType in [stString, stUnicodeString, stBytes, stGUID,
270 stAsciiStream, stUnicodeStream, stBinaryStream];
272 Result := InitialType in [stString, stUnicodeString, stDate, stTime, stTimestamp];
274 Result := InitialType in [stString, stUnicodeString, stDate, stTimestamp];
276 Result := InitialType in [stString, stUnicodeString, stTime, stTimestamp];
278 Result := (ResultType = InitialType) and (InitialType <> stUnknown);
283 Defines a name of the column type.
284 @param ColumnType a type of the column.
285 @return a name of the specified type.
287 function DefineColumnTypeName(ColumnType: TZSQLType): string;
305 Result := 'BigDecimal';
309 Result := 'UnicodeString';
319 Result := 'Timestamp';
321 Result := 'AsciiStream';
323 Result := 'UnicodeStream';
325 Result := 'BinaryStream';
332 Raises a copy of the given exception.
333 @param E an exception to be raised.
335 procedure RaiseSQLException(E: Exception);
337 if E is EZSQLException then
339 raise EZSQLException.CreateClone(EZSQLException(E));
343 raise EZSQLException.Create(E.Message);
348 Copies column information objects from one object list to another one.
349 @param FromList the source object list.
350 @param ToList the destination object list.
352 procedure CopyColumnsInfo(FromList: TObjectList; ToList: TObjectList);
355 Current: TZColumnInfo;
356 ColumnInfo: TZColumnInfo;
358 for I := 0 to FromList.Count - 1 do
360 Current := TZColumnInfo(FromList[I]);
361 ColumnInfo := TZColumnInfo.Create;
363 ColumnInfo.AutoIncrement := Current.AutoIncrement;
364 ColumnInfo.CaseSensitive := Current.CaseSensitive;
365 ColumnInfo.Searchable := Current.Searchable;
366 ColumnInfo.Currency := Current.Currency;
367 ColumnInfo.Nullable := Current.Nullable;
368 ColumnInfo.Signed := Current.Signed;
369 ColumnInfo.ColumnDisplaySize := Current.ColumnDisplaySize;
370 ColumnInfo.ColumnLabel := Current.ColumnLabel;
371 ColumnInfo.ColumnName := Current.ColumnName;
372 ColumnInfo.SchemaName := Current.SchemaName;
373 ColumnInfo.Precision := Current.Precision;
374 ColumnInfo.Scale := Current.Scale;
375 ColumnInfo.TableName := Current.TableName;
376 ColumnInfo.CatalogName := Current.CatalogName;
377 ColumnInfo.ColumnType := Current.ColumnType;
378 ColumnInfo.ReadOnly := Current.ReadOnly;
379 ColumnInfo.Writable := Current.Writable;
380 ColumnInfo.DefinitelyWritable := Current.DefinitelyWritable;
382 ToList.Add(ColumnInfo);
387 Defines a statement specific parameter.
388 @param Statement a statement interface reference.
389 @param ParamName a name of the parameter.
390 @param Default a parameter default value.
391 @return a parameter value or default if nothing was found.
393 function DefineStatementParameter(Statement: IZStatement; const ParamName: string;
394 const Default: string): string;
396 Result := Statement.GetParameters.Values[ParamName];
398 Result := Statement.GetConnection.GetParameters.Values[ParamName];
404 ToLikeString returns the given string or if the string is empty it returns '%'
405 @param Value the string
406 @return given Value or '%'
408 function ToLikeString(const Value: string): string;
417 GetSQLHexString returns a valid x'..' database understandable String from
419 @param Value the ansistring-pointer to the binary data
420 @param Length then length of the binary Data
421 @param ODBC a boolean if output result should be with a starting 0x...
422 @returns a valid hex formated unicode-safe string
425 function GetSQLHexWideString(Value: PAnsiChar; Len: Integer; ODBC: Boolean = False): ZWideString;
429 SetLength(HexVal,Len * 2 );
430 BinToHex(Value, PAnsiChar(HexVal), Len);
433 Result := '0x'+ZWideString(HexVal)
435 Result := 'x'#39+ZWideString(HexVal)+#39;
438 function GetSQLHexAnsiString(Value: PAnsiChar; Len: Integer; ODBC: Boolean = False): RawByteString;
440 HexVal: RawByteString;
442 SetLength(HexVal,Len * 2 );
443 BinToHex(Value, PAnsiChar(HexVal), Len);
446 Result := '0x'+HexVal
448 Result := 'x'#39+HexVal+#39;
451 function GetSQLHexString(Value: PAnsiChar; Len: Integer; ODBC: Boolean = False): String;
454 Result := GetSQLHexWideString(Value, Len, ODBC);
456 Result := GetSQLHexAnsiString(Value, Len, ODBC);
461 Returns a FieldSize in Bytes dependend to the FieldType and CharWidth
462 @param <code>TZSQLType</code> the Zeos FieldType
463 @param <code>Integer</code> the Current given FieldLength
464 @param <code>Integer</code> the Current CountOfByte/Char
465 @param <code>Boolean</code> does the Driver returns the FullSizeInBytes
466 @returns <code>Integer</code> the count of AnsiChars for Field.Size * SizeOf(Char)
468 function GetFieldSize(const SQLType: TZSQLType; ConSettings: PZConSettings;
469 const Precision, CharWidth: Integer; DisplaySize: PInteger = nil;
470 SizeInBytes: Boolean = False): Integer;
472 TempPrecision: Integer;
474 if ( SQLType in [stString, stUnicodeString] ) and ( Precision <> 0 )then
477 TempPrecision := Precision div CharWidth
479 TempPrecision := Precision;
481 if Assigned(DisplaySize) then
482 DisplaySize^ := TempPrecision;
484 if SQLType = stString then
485 //the RowAccessor assumes SizeOf(Char)*Precision+SizeOf(Char)
486 //the Field assumes Precision*SizeOf(Char)
488 if ConSettings.ClientCodePage.CharWidth >= 2 then //All others > 3 are UTF8
489 Result := TempPrecision * 2 //add more mem for a reserved thirt byte
490 else //two and one byte AnsiChars are one WideChar
491 Result := TempPrecision
493 if ( ConSettings.CPType = cCP_UTF8 ) or (ConSettings.CTRL_CP = zCP_UTF8) then
494 Result := TempPrecision * 4
496 Result := TempPrecision * CharWidth
498 else //stUnicodeString
499 //UTF8 can pickup LittleEndian/BigEndian 4 Byte Chars
500 //the RowAccessor assumes 2*Precision+2!
501 //the Field assumes 2*Precision ??Does it?
502 if CharWidth > 2 then
503 Result := TempPrecision * 2
505 Result := TempPrecision;
511 function WideStringStream(const AString: WideString): TStream;
513 Result := TMemoryStream.Create;
514 Result.Write(PWideChar(AString)^, Length(AString)*2);
515 Result.Position := 0;