diff --git a/components/zeosdbo/src/dbc/ZDbcMySql.pas b/components/zeosdbo/src/dbc/ZDbcMySql.pas index 0c843f3a..72e25546 100644 --- a/components/zeosdbo/src/dbc/ZDbcMySql.pas +++ b/components/zeosdbo/src/dbc/ZDbcMySql.pas @@ -440,13 +440,9 @@ begin DriverManager.LogMessage(lcConnect, FPlainDriver.GetProtocol, LogMessage); { Sets a client codepage. } - if FClientCodePage <> '' then - begin - SQL := PChar(Format('SET CHARACTER SET %s', [FClientCodePage])); - FPlainDriver.ExecQuery(FHandle, SQL); - CheckMySQLError(FPlainDriver, FHandle, lcExecute, SQL); - DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, SQL); - end; + FPlainDriver.SetCharacterSet(FHandle, 'utf8'); + CheckMySQLError(FPlainDriver, FHandle, lcExecute, LogMessage); + DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogMessage); { Sets transaction isolation level. } OldLevel := TransactIsolationLevel; diff --git a/components/zeosdbo/src/dbc/ZDbcMySqlMetadata.pas b/components/zeosdbo/src/dbc/ZDbcMySqlMetadata.pas index 07ce6b30..9016c25b 100644 --- a/components/zeosdbo/src/dbc/ZDbcMySqlMetadata.pas +++ b/components/zeosdbo/src/dbc/ZDbcMySqlMetadata.pas @@ -2130,9 +2130,9 @@ const TypeCodes: array[1..MaxTypeCount] of TZSQLType = ( stBinaryStream, stBoolean, stShort, stLong, stBinaryStream, stBinaryStream, stBinaryStream, stBinaryStream, stBinaryStream, stBytes, stBytes, - stString, stAsciiStream, stAsciiStream, stAsciiStream, stAsciiStream, - stString, stString, stBigDecimal, stBigDecimal, stInteger, stInteger, - stInteger, stShort, stDouble, stFloat, stFloat, stString, stString, + stUnicodeString, stUnicodeStream, stUnicodeStream, stUnicodeStream, stUnicodeStream, + stUnicodeString, stUnicodeString, stBigDecimal, stBigDecimal, stInteger, stInteger, + stInteger, stShort, stDouble, stFloat, stFloat, stUnicodeString, stUnicodeString, stDate, stTime, stTimestamp, stTimestamp); TypePrecision: array[1..MaxTypeCount] of Integer = ( 64, -1, 4, 16, 16777215, 16777215, MAXBUF, 65535, 255, 255, 255, diff --git a/components/zeosdbo/src/dbc/ZDbcMySqlResultSet.pas b/components/zeosdbo/src/dbc/ZDbcMySqlResultSet.pas index 770b361f..05d7d004 100644 --- a/components/zeosdbo/src/dbc/ZDbcMySqlResultSet.pas +++ b/components/zeosdbo/src/dbc/ZDbcMySqlResultSet.pas @@ -92,6 +92,7 @@ type function IsNull(ColumnIndex: Integer): Boolean; override; function GetPChar(ColumnIndex: Integer): PChar; override; function GetString(ColumnIndex: Integer): string; override; + function GetUnicodeString(ColumnIndex: Integer): WideString; override; function GetBoolean(ColumnIndex: Integer): Boolean; override; function GetByte(ColumnIndex: Integer): ShortInt; override; function GetShort(ColumnIndex: Integer): SmallInt; override; @@ -388,6 +389,11 @@ begin SetString(Result, Buffer, Length); end; +function TZMySQLResultSet.GetUnicodeString(ColumnIndex: Integer): WideString; +begin + Result := UTF8Decode(GetString(ColumnIndex)); +end; + {** Gets the value of the designated column in the current row of this ResultSet object as @@ -693,11 +699,15 @@ end; NULL, the value returned is null } function TZMySQLResultSet.GetUnicodeStream(ColumnIndex: Integer): TStream; +var + s: WideString; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stUnicodeStream); {$ENDIF} - Result := nil; + s := GetUnicodeString(ColumnIndex); + Result := TMemoryStream.Create; + Result.WriteBuffer(s[1], Length(s) * SizeOf(s[1])); end; {** diff --git a/components/zeosdbo/src/dbc/ZDbcMySqlStatement.pas b/components/zeosdbo/src/dbc/ZDbcMySqlStatement.pas index 3a528fc8..f13b7f2e 100644 --- a/components/zeosdbo/src/dbc/ZDbcMySqlStatement.pas +++ b/components/zeosdbo/src/dbc/ZDbcMySqlStatement.pas @@ -97,7 +97,7 @@ type FPlainDriver: IZMySQLPlainDriver; protected function CreateExecStatement: IZStatement; override; - function GetEscapeString(const Value: string): string; + function GetEscapeString(const Value: WideString): WideString; function PrepareSQLParam(ParamIndex: Integer): string; override; public constructor Create(PlainDriver: IZMySQLPlainDriver; @@ -329,15 +329,15 @@ end; @param Value a regular string. @return a string in MySQL escape format. } -function TZMySQLPreparedStatement.GetEscapeString(const Value: string): string; +function TZMySQLPreparedStatement.GetEscapeString(const Value: WideString): WideString; var BufferLen: Integer; Buffer: PChar; begin BufferLen := Length(Value) * 2 + 1; GetMem(Buffer, BufferLen); - BufferLen := FPlainDriver.GetEscapeString(FHandle, Buffer, PChar(Value), Length(Value)); - Result := '''' + BufferToStr(Buffer, BufferLen) + ''''; + BufferLen := FPlainDriver.GetEscapeString(FHandle, Buffer, PChar(UTF8Encode(Value)), Length(Value)); + Result := '''' + UTF8Decode(BufferToStr(Buffer, BufferLen)) + ''''; FreeMem(Buffer); end; @@ -374,6 +374,8 @@ begin Result := SoftVarManager.GetAsString(Value); stString, stBytes: Result := GetEscapeString(SoftVarManager.GetAsString(Value)); + stUnicodeString: + Result := GetEscapeString(SoftVarManager.GetAsUnicodeString(Value)); stDate: begin {$IFNDEF VER130BELOW} diff --git a/components/zeosdbo/src/dbc/ZDbcMySqlUtils.pas b/components/zeosdbo/src/dbc/ZDbcMySqlUtils.pas index 93482f73..a823d145 100644 --- a/components/zeosdbo/src/dbc/ZDbcMySqlUtils.pas +++ b/components/zeosdbo/src/dbc/ZDbcMySqlUtils.pas @@ -192,7 +192,7 @@ begin begin if Signed then Result := stLong //else Result := stBigDecimal; - else Result := stString; + else Result := stUnicodeString; end; FIELD_TYPE_FLOAT: // Result := stFloat; @@ -211,34 +211,34 @@ begin Result := stDouble; FIELD_TYPE_DATE, FIELD_TYPE_NEWDATE: //Result := stDate; - Result := stString; + Result := stUnicodeString; FIELD_TYPE_TIME: //Result := stTime; - Result := stString; + Result := stUnicodeString; FIELD_TYPE_DATETIME, FIELD_TYPE_TIMESTAMP: //Result := stTimestamp; - Result := stString; + Result := stUnicodeString; FIELD_TYPE_TINY_BLOB, FIELD_TYPE_MEDIUM_BLOB, FIELD_TYPE_LONG_BLOB, FIELD_TYPE_BLOB: if (FieldFlags and BINARY_FLAG) = 0 then - Result := stAsciiStream + Result := stUnicodeStream else Result := stBinaryStream; FIELD_TYPE_BIT: Result := stBinaryStream; FIELD_TYPE_VARCHAR: - Result := stString; + Result := stUnicodeString; FIELD_TYPE_VAR_STRING: - Result := stString; + Result := stUnicodeString; FIELD_TYPE_STRING: - Result := stString; + Result := stUnicodeString; FIELD_TYPE_ENUM: - Result := stString; + Result := stUnicodeString; FIELD_TYPE_SET: - Result := stString; + Result := stUnicodeString; FIELD_TYPE_NULL: // Example: SELECT NULL FROM DUAL // Todo: Find out if it is possible to get real data in a TYPE_NULL field, perhaps adjust to binary or some such? - Result := stString; + Result := stUnicodeString; FIELD_TYPE_GEOMETRY: // Todo: Would be nice to show as WKT. Result := stBinaryStream; @@ -246,7 +246,7 @@ begin raise Exception.Create('Unknown MySQL data type!'); end; { SHOW FULL PROCESSLIST on 4.x servers can return veeery long FIELD_TYPE_VAR_STRINGs. The following helps avoid excessive row buffer allocation later on. } - if (Result = stString) and (PlainDriver.GetFieldLength(FieldHandle) > 8192) then Result := stAsciiStream; + if (Result = stUnicodeString) and (PlainDriver.GetFieldLength(FieldHandle) > 8192) then Result := stUnicodeStream; end; {** @@ -304,7 +304,7 @@ begin begin // Zeos uses a floating point type for unsigned int64.. //if IsUnsigned then Result := stBigDecimal - if IsUnsigned then Result := stString + if IsUnsigned then Result := stUnicodeString else Result := stLong; end else if TypeName = 'INT24' then @@ -335,21 +335,21 @@ begin else if TypeName = 'DOUBLE' then Result := stDouble else if TypeName = 'CHAR' then - Result := stString + Result := stUnicodeString else if TypeName = 'VARCHAR' then - Result := stString + Result := stUnicodeString else if TypeName = 'VARBINARY' then Result := stBytes else if TypeName = 'BINARY' then Result := stBytes else if TypeName = 'DATE' then - Result := stString + Result := stUnicodeString else if TypeName = 'TIME' then - Result := stString + Result := stUnicodeString else if TypeName = 'TIMESTAMP' then - Result := stString + Result := stUnicodeString else if TypeName = 'DATETIME' then - Result := stString + Result := stUnicodeString else if TypeName = 'TINYBLOB' then Result := stBinaryStream else if TypeName = 'BLOB' then @@ -359,17 +359,17 @@ begin else if TypeName = 'LONGBLOB' then Result := stBinaryStream else if TypeName = 'TINYTEXT' then - Result := stAsciiStream + Result := stUnicodeStream else if TypeName = 'TEXT' then - Result := stAsciiStream + Result := stUnicodeStream else if TypeName = 'MEDIUMTEXT' then - Result := stAsciiStream + Result := stUnicodeStream else if TypeName = 'LONGTEXT' then - Result := stAsciiStream + Result := stUnicodeStream else if TypeName = 'ENUM' then - Result := stString + Result := stUnicodeString else if TypeName = 'SET' then - Result := stString + Result := stUnicodeString else if TypeName = 'BIT' then Result := stBinaryStream else for i := 0 to Length(GeoTypes)-1 do if GeoTypes[i] = TypeName then Result := stBinaryStream; diff --git a/components/zeosdbo/src/plain/ZPlainMySqlDriver.pas b/components/zeosdbo/src/plain/ZPlainMySqlDriver.pas index d76b1bcc..3ba3573b 100644 --- a/components/zeosdbo/src/plain/ZPlainMySqlDriver.pas +++ b/components/zeosdbo/src/plain/ZPlainMySqlDriver.pas @@ -188,6 +188,7 @@ type function GetAffectedRows(Handle: PZMySQLConnect): Int64; // char_set_name + procedure SetCharacterSet(Handle: PZMySQLConnect; const CharSet: PChar); procedure Close(Handle: PZMySQLConnect); function Connect(Handle: PZMySQLConnect; const Host, User, Password: PChar): PZMySQLConnect; function CreateDatabase(Handle: PZMySQLConnect; const Database: PChar): Integer; @@ -786,6 +787,7 @@ type function StoreResult(Handle: PZMySQLConnect): PZMySQLResult; function UseResult(Handle: PZMySQLConnect): PZMySQLResult; procedure FreeResult(Res: PZMySQLResult); + procedure SetCharacterSet(Handle: PZMySQLConnect; const CharSet: PChar); function GetAffectedRows(Handle: PZMySQLConnect): Int64; function FetchRow(Res: PZMySQLResult): PZMySQLRow; @@ -869,6 +871,7 @@ type function Rollback (Handle: PZMySQLConnect): Boolean; function GetSQLState (Handle: PZMySQLConnect): AnsiString; + procedure SetCharacterSet(Handle: PZMySQLConnect; const CharSet: PChar); function GetPreparedAffectedRows (Handle: PZMySqlPrepStmt): Int64; function BindParameters (Handle: PZMySqlPrepStmt; bindArray: PZMysqlBindArray): Byte; function BindResult (Handle: PZMySqlPrepStmt; bindArray: PZMysqlBindArray): Byte; @@ -2583,6 +2586,11 @@ begin MYSQL_API.mysql_free_result(Res); end; +procedure TZMySQL41PlainDriver.SetCharacterSet(Handle: PZMySQLConnect; const CharSet: PChar); +begin + MYSQL_API.mysql_set_character_set(Handle, CharSet); +end; + function TZMySQL41PlainDriver.GetAffectedRows(Handle: PZMySQLConnect): Int64; begin Result := MYSQL_API.mysql_affected_rows(Handle); @@ -3108,6 +3116,11 @@ begin MYSQL_API.mysql_free_result(Res); end; +procedure TZMySQL5PlainDriver.SetCharacterSet(Handle: PZMySQLConnect; const CharSet: PChar); +begin + MYSQL_API.mysql_set_character_set(Handle, CharSet); +end; + function TZMySQL5PlainDriver.GetAffectedRows(Handle: PZMySQLConnect): Int64; begin Result := MYSQL_API.mysql_affected_rows(Handle);