aboutsummaryrefslogtreecommitdiffstats
path: root/Frameworks
diff options
context:
space:
mode:
Diffstat (limited to 'Frameworks')
-rw-r--r--Frameworks/PostgresKit/PostgresKit.xcodeproj/project.pbxproj44
-rw-r--r--Frameworks/PostgresKit/PostgresKit.xcodeproj/xcshareddata/xcschemes/PostgresKit.xcscheme16
-rw-r--r--Frameworks/PostgresKit/Resources/Info.plist2
-rw-r--r--Frameworks/PostgresKit/Resources/Tests-Info.plist2
-rw-r--r--Frameworks/PostgresKit/Tests/PGDataTypeTests.h2
-rw-r--r--Frameworks/PostgresKit/Tests/PGDataTypeTests.m12
-rw-r--r--Frameworks/PostgresKit/Tests/PGPostgresIntegrationTestCase.h4
-rw-r--r--Frameworks/PostgresKit/Tests/PGPostgresIntegrationTestCase.m16
-rw-r--r--Frameworks/PostgresKit/Tests/PGPostgresResultTests.h2
-rw-r--r--Frameworks/PostgresKit/Tests/PGPostgresResultTests.m4
-rw-r--r--Frameworks/QueryKit/QueryKit.xcodeproj/project.pbxproj50
-rw-r--r--Frameworks/QueryKit/QueryKit.xcodeproj/xcshareddata/xcschemes/QueryKit.xcscheme16
-rw-r--r--Frameworks/QueryKit/Resources/Info.plist2
-rw-r--r--Frameworks/QueryKit/Resources/Tests-Info.plist2
-rw-r--r--Frameworks/QueryKit/Tests/QKDeleteQueryTests.h4
-rw-r--r--Frameworks/QueryKit/Tests/QKDeleteQueryTests.m16
-rw-r--r--Frameworks/QueryKit/Tests/QKQueryTests.m24
-rw-r--r--Frameworks/QueryKit/Tests/QKSelectQueryGroupByTests.h4
-rw-r--r--Frameworks/QueryKit/Tests/QKSelectQueryGroupByTests.m12
-rw-r--r--Frameworks/QueryKit/Tests/QKSelectQueryOrderByTests.h4
-rw-r--r--Frameworks/QueryKit/Tests/QKSelectQueryOrderByTests.m16
-rw-r--r--Frameworks/QueryKit/Tests/QKSelectQueryTests.h4
-rw-r--r--Frameworks/QueryKit/Tests/QKSelectQueryTests.m16
-rw-r--r--Frameworks/QueryKit/Tests/QKTestCase.h4
-rw-r--r--Frameworks/QueryKit/Tests/QKUpdateQueryTests.h4
-rw-r--r--Frameworks/QueryKit/Tests/QKUpdateQueryTests.m14
-rw-r--r--Frameworks/SPMySQLFramework/MySQL Client Libraries/include/mysql_com.h6
-rw-r--r--Frameworks/SPMySQLFramework/Resources/Info.plist2
-rw-r--r--Frameworks/SPMySQLFramework/SPMySQL Unit Tests/DataConversion_Tests.m77
-rw-r--r--Frameworks/SPMySQLFramework/SPMySQL Unit Tests/Info.plist24
-rw-r--r--Frameworks/SPMySQLFramework/SPMySQL Unit Tests/SPMySQLStringAdditions_Tests.m89
-rw-r--r--Frameworks/SPMySQLFramework/SPMySQLDataTypes.h1
-rw-r--r--Frameworks/SPMySQLFramework/SPMySQLDataTypes.m1
-rw-r--r--Frameworks/SPMySQLFramework/SPMySQLFramework.xcodeproj/project.pbxproj305
-rw-r--r--Frameworks/SPMySQLFramework/SPMySQLFramework.xcodeproj/xcshareddata/xcschemes/SPMySQL.framework.xcscheme99
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQL Private APIs.h8
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Encoding.m6
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Ping & KeepAlive.h6
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Ping & KeepAlive.m66
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Querying & Preparation.m34
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Server Info.h10
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Server Info.m76
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLConnection.h9
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m114
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLFastStreamingResult.m4
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLResult Categories/Data Conversion.h7
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLResult Categories/Data Conversion.m49
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLResult Categories/Field Definitions.m14
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLResult.m2
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLStreamingResultStore.h8
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLStreamingResultStore.m4
51 files changed, 1022 insertions, 295 deletions
diff --git a/Frameworks/PostgresKit/PostgresKit.xcodeproj/project.pbxproj b/Frameworks/PostgresKit/PostgresKit.xcodeproj/project.pbxproj
index 479474da..bf8e5545 100644
--- a/Frameworks/PostgresKit/PostgresKit.xcodeproj/project.pbxproj
+++ b/Frameworks/PostgresKit/PostgresKit.xcodeproj/project.pbxproj
@@ -81,7 +81,7 @@
1724CA3B15F9EE7300AB2291 /* libpqtypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libpqtypes.h; sourceTree = "<group>"; };
1724CC9015FB4CC200AB2291 /* PGPostgresTimeTZ.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PGPostgresTimeTZ.h; sourceTree = "<group>"; };
1724CC9115FB4CC200AB2291 /* PGPostgresTimeTZ.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PGPostgresTimeTZ.m; sourceTree = "<group>"; };
- 1724CD0415FB68E800AB2291 /* Tests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.octest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 1724CD0415FB68E800AB2291 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
1724CD0515FB68E800AB2291 /* Tests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Tests-Info.plist"; path = "Resources/Tests-Info.plist"; sourceTree = "<group>"; };
1724CD5715FB8A3300AB2291 /* PGPostgresTimeInterval.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PGPostgresTimeInterval.h; sourceTree = "<group>"; };
1724CD5815FB8A3300AB2291 /* PGPostgresTimeInterval.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PGPostgresTimeInterval.m; sourceTree = "<group>"; };
@@ -167,7 +167,7 @@
isa = PBXGroup;
children = (
8DC2EF5B0486A6940098B216 /* PostgresKit.framework */,
- 1724CD0415FB68E800AB2291 /* Tests.octest */,
+ 1724CD0415FB68E800AB2291 /* Tests.xctest */,
);
name = Products;
sourceTree = "<group>";
@@ -460,8 +460,8 @@
);
name = Tests;
productName = Tests;
- productReference = 1724CD0415FB68E800AB2291 /* Tests.octest */;
- productType = "com.apple.product-type.bundle";
+ productReference = 1724CD0415FB68E800AB2291 /* Tests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
};
8DC2EF4F0486A6940098B216 /* PostgresKit */ = {
isa = PBXNativeTarget;
@@ -487,7 +487,7 @@
0867D690FE84028FC02AAC07 /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 0500;
+ LastUpgradeCheck = 0720;
};
buildConfigurationList = 1DEB91B108733DA50010E9CD /* Build configuration list for PBXProject "PostgresKit" */;
compatibilityVersion = "Xcode 3.2";
@@ -565,7 +565,7 @@
CLANG_LINK_OBJC_RUNTIME = NO;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
- FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks";
+ FRAMEWORK_SEARCH_PATHS = "$(inherited)";
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
@@ -576,12 +576,9 @@
OTHER_LDFLAGS = (
"-framework",
Cocoa,
- "-framework",
- SenTestingKit,
);
+ PRODUCT_BUNDLE_IDENTIFIER = com.sequelpro.postgreskit.tests;
PRODUCT_NAME = Tests;
- TEST_AFTER_BUILD = YES;
- WRAPPER_EXTENSION = octest;
};
name = Debug;
};
@@ -592,7 +589,7 @@
CLANG_LINK_OBJC_RUNTIME = NO;
COMBINE_HIDPI_IMAGES = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks";
+ FRAMEWORK_SEARCH_PATHS = "$(inherited)";
GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
@@ -601,12 +598,9 @@
OTHER_LDFLAGS = (
"-framework",
Cocoa,
- "-framework",
- SenTestingKit,
);
+ PRODUCT_BUNDLE_IDENTIFIER = com.sequelpro.postgreskit.tests;
PRODUCT_NAME = Tests;
- TEST_AFTER_BUILD = YES;
- WRAPPER_EXTENSION = octest;
ZERO_LINK = NO;
};
name = Release;
@@ -617,7 +611,7 @@
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_LINK_OBJC_RUNTIME = NO;
COMBINE_HIDPI_IMAGES = YES;
- FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks";
+ FRAMEWORK_SEARCH_PATHS = "$(inherited)";
GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
@@ -626,12 +620,9 @@
OTHER_LDFLAGS = (
"-framework",
Cocoa,
- "-framework",
- SenTestingKit,
);
+ PRODUCT_BUNDLE_IDENTIFIER = com.sequelpro.postgreskit.tests;
PRODUCT_NAME = Tests;
- TEST_AFTER_BUILD = YES;
- WRAPPER_EXTENSION = octest;
};
name = Distribution;
};
@@ -645,8 +636,11 @@
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "Source/PostgresKit-Prefix.pch";
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
@@ -704,6 +698,7 @@
"$(inherited)",
"\"$(SRCROOT)/Libs\"/**",
);
+ PRODUCT_BUNDLE_IDENTIFIER = com.sequelpro.postgreskit;
PRODUCT_NAME = PostgresKit;
WARNING_CFLAGS = "-Wmost";
WRAPPER_EXTENSION = framework;
@@ -756,6 +751,7 @@
"$(inherited)",
"\"$(SRCROOT)/Libs\"/**",
);
+ PRODUCT_BUNDLE_IDENTIFIER = com.sequelpro.postgreskit;
PRODUCT_NAME = PostgresKit;
WARNING_CFLAGS = "-Wmost";
WRAPPER_EXTENSION = framework;
@@ -803,6 +799,7 @@
"$(inherited)",
"\"$(SRCROOT)/Libs\"/**",
);
+ PRODUCT_BUNDLE_IDENTIFIER = com.sequelpro.postgreskit;
PRODUCT_NAME = PostgresKit;
WARNING_CFLAGS = "-Wmost";
WRAPPER_EXTENSION = framework;
@@ -819,8 +816,12 @@
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "Source/PostgresKit-Prefix.pch";
@@ -849,8 +850,11 @@
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "Source/PostgresKit-Prefix.pch";
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
diff --git a/Frameworks/PostgresKit/PostgresKit.xcodeproj/xcshareddata/xcschemes/PostgresKit.xcscheme b/Frameworks/PostgresKit/PostgresKit.xcodeproj/xcshareddata/xcschemes/PostgresKit.xcscheme
index ca74a70b..04dd4bea 100644
--- a/Frameworks/PostgresKit/PostgresKit.xcodeproj/xcshareddata/xcschemes/PostgresKit.xcscheme
+++ b/Frameworks/PostgresKit/PostgresKit.xcodeproj/xcshareddata/xcschemes/PostgresKit.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "0500"
+ LastUpgradeVersion = "0720"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -33,12 +33,14 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "1724CD0315FB68E800AB2291"
- BuildableName = "Tests.octest"
+ BuildableName = "Tests.xctest"
BlueprintName = "Tests"
ReferencedContainer = "container:PostgresKit.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
+ <AdditionalOptions>
+ </AdditionalOptions>
</TestAction>
<LaunchAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
@@ -48,7 +50,17 @@
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
+ debugServiceExtension = "internal"
allowLocationSimulation = "YES">
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "8DC2EF4F0486A6940098B216"
+ BuildableName = "PostgresKit.framework"
+ BlueprintName = "PostgresKit"
+ ReferencedContainer = "container:PostgresKit.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
diff --git a/Frameworks/PostgresKit/Resources/Info.plist b/Frameworks/PostgresKit/Resources/Info.plist
index b961331f..0da2c36b 100644
--- a/Frameworks/PostgresKit/Resources/Info.plist
+++ b/Frameworks/PostgresKit/Resources/Info.plist
@@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>PostgresKit</string>
<key>CFBundleIdentifier</key>
- <string>com.sequelpro.postgreskit</string>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
diff --git a/Frameworks/PostgresKit/Resources/Tests-Info.plist b/Frameworks/PostgresKit/Resources/Tests-Info.plist
index b88d8638..ddbc4bf7 100644
--- a/Frameworks/PostgresKit/Resources/Tests-Info.plist
+++ b/Frameworks/PostgresKit/Resources/Tests-Info.plist
@@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>Tests</string>
<key>CFBundleIdentifier</key>
- <string>com.sequelpro.postgreskit.tests</string>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
diff --git a/Frameworks/PostgresKit/Tests/PGDataTypeTests.h b/Frameworks/PostgresKit/Tests/PGDataTypeTests.h
index 8f6b54ad..7322823f 100644
--- a/Frameworks/PostgresKit/Tests/PGDataTypeTests.h
+++ b/Frameworks/PostgresKit/Tests/PGDataTypeTests.h
@@ -27,7 +27,7 @@
// OTHER DEALINGS IN THE SOFTWARE.
#import <PostgresKit/PostgresKit.h>
-#import <SenTestingKit/SenTestingKit.h>
+#import <XCTest/XCTest.h>
#import "PGPostgresIntegrationTestCase.h"
diff --git a/Frameworks/PostgresKit/Tests/PGDataTypeTests.m b/Frameworks/PostgresKit/Tests/PGDataTypeTests.m
index a2048ed6..8ffd8b47 100644
--- a/Frameworks/PostgresKit/Tests/PGDataTypeTests.m
+++ b/Frameworks/PostgresKit/Tests/PGDataTypeTests.m
@@ -33,7 +33,7 @@
+ (void)_addTestForField:(NSString *)field
withExpectedResult:(id)result
connection:(PGPostgresConnection *)connection
- toTestSuite:(SenTestSuite *)testSuite;
+ toTestSuite:(XCTestSuite *)testSuite;
@end
@@ -48,7 +48,7 @@
+ (id)defaultTestSuite
{
- SenTestSuite *testSuite = [[SenTestSuite alloc] initWithName:[self className]];
+ XCTestSuite *testSuite = [[XCTestSuite alloc] initWithName:[self className]];
PGPostgresConnection *connection = [[PGPostgresConnection alloc] init];
@@ -109,12 +109,12 @@
- (void)testResultValueIsNotNil
{
- STAssertNotNil(_result, nil);
+ XCTAssertNotNil(_result);
}
- (void)testResultIsOfCorrectTypeAndValue
{
- STAssertEqualObjects(_result, _expectedResult, nil);
+ XCTAssertEqualObjects(_result, _expectedResult);
}
#pragma mark -
@@ -123,11 +123,11 @@
+ (void)_addTestForField:(NSString *)field
withExpectedResult:(id)result
connection:(PGPostgresConnection *)connection
- toTestSuite:(SenTestSuite *)testSuite
+ toTestSuite:(XCTestSuite *)testSuite
{
for (NSInvocation *invocation in [self testInvocations])
{
- SenTestCase *test = [[[self class] alloc] initWithInvocation:invocation connection:connection expectedResult:result field:field];
+ XCTestCase *test = [[[self class] alloc] initWithInvocation:invocation connection:connection expectedResult:result field:field];
[testSuite addTest:test];
diff --git a/Frameworks/PostgresKit/Tests/PGPostgresIntegrationTestCase.h b/Frameworks/PostgresKit/Tests/PGPostgresIntegrationTestCase.h
index c6706156..7a654f5f 100644
--- a/Frameworks/PostgresKit/Tests/PGPostgresIntegrationTestCase.h
+++ b/Frameworks/PostgresKit/Tests/PGPostgresIntegrationTestCase.h
@@ -27,9 +27,9 @@
// OTHER DEALINGS IN THE SOFTWARE.
#import <PostgresKit/PostgresKit.h>
-#import <SenTestingKit/SenTestingKit.h>
+#import <XCTest/XCTest.h>
-@interface PGPostgresIntegrationTestCase : SenTestCase
+@interface PGPostgresIntegrationTestCase : XCTestCase
{
PGPostgresConnection *_connection;
}
diff --git a/Frameworks/PostgresKit/Tests/PGPostgresIntegrationTestCase.m b/Frameworks/PostgresKit/Tests/PGPostgresIntegrationTestCase.m
index e6c96505..231e1bfa 100644
--- a/Frameworks/PostgresKit/Tests/PGPostgresIntegrationTestCase.m
+++ b/Frameworks/PostgresKit/Tests/PGPostgresIntegrationTestCase.m
@@ -35,6 +35,8 @@ static NSString *PGTestDatabasePassword = @"pgkit";
static NSUInteger PGTestDatabasePort = 5432;
+static double PGTestConnectionTimeout = 0.2;
+
@interface PGPostgresIntegrationTestCase ()
- (void)_establishConnection;
@@ -67,13 +69,25 @@ static NSUInteger PGTestDatabasePort = 5432;
[_connection setPassword:PGTestDatabasePassword];
if (![_connection connect]) {
- STFail(@"Request to establish connection to local database failed.");
+ XCTFail(@"Request to establish connection to local database failed.");
exit(1);
}
+ NSDate *startDate = [NSDate date];
+
do {
sleep(0.1);
+
+ if([[NSDate date] timeIntervalSinceDate:startDate] > PGTestConnectionTimeout) {
+ XCTFail(@"Failed to connect to database after %f seconds. Host:%@ Database:%@ User:%@ Password:%@",
+ PGTestConnectionTimeout,
+ PGTestDatabaseHost,
+ PGTestDatabaseName,
+ PGTestDatabaseUser,
+ PGTestDatabasePassword);
+ exit(1);
+ }
}
while (![_connection isConnected]);
}
diff --git a/Frameworks/PostgresKit/Tests/PGPostgresResultTests.h b/Frameworks/PostgresKit/Tests/PGPostgresResultTests.h
index 93c36427..e01aedec 100644
--- a/Frameworks/PostgresKit/Tests/PGPostgresResultTests.h
+++ b/Frameworks/PostgresKit/Tests/PGPostgresResultTests.h
@@ -27,7 +27,7 @@
// OTHER DEALINGS IN THE SOFTWARE.
#import <PostgresKit/PostgresKit.h>
-#import <SenTestingKit/SenTestingKit.h>
+#import <XCTest/XCTest.h>
#import "PGPostgresIntegrationTestCase.h"
diff --git a/Frameworks/PostgresKit/Tests/PGPostgresResultTests.m b/Frameworks/PostgresKit/Tests/PGPostgresResultTests.m
index ef64ea53..8e27b163 100644
--- a/Frameworks/PostgresKit/Tests/PGPostgresResultTests.m
+++ b/Frameworks/PostgresKit/Tests/PGPostgresResultTests.m
@@ -63,7 +63,7 @@
"}");
// Compare the output after getting rid of newlines and spaces
- STAssertTrue([[[[_result description] stringByReplacingOccurrencesOfString:@"\n" withString:@""] stringByReplacingOccurrencesOfString:@" " withString:@""] isEqualToString:@"{"
+ XCTAssertTrue([[[[_result description] stringByReplacingOccurrencesOfString:@"\n" withString:@""] stringByReplacingOccurrencesOfString:@" " withString:@""] isEqualToString:@"{"
"\"bigint_field\" = 123456789;"
"\"bool_field\" = 1;"
"\"char_field\" = CHAR;"
@@ -77,7 +77,7 @@
"\"timestamptz_field\" = \"8 Apr 1987 03:02:02 GMT+01:00\";"
"\"timetz_field\" = \"02:02:02 GMT+10:00\";"
"\"varchar_field\" = VARCHAR;"
- "}"], nil);
+ "}"]);
}
#pragma mark -
diff --git a/Frameworks/QueryKit/QueryKit.xcodeproj/project.pbxproj b/Frameworks/QueryKit/QueryKit.xcodeproj/project.pbxproj
index 62059d07..52ef1774 100644
--- a/Frameworks/QueryKit/QueryKit.xcodeproj/project.pbxproj
+++ b/Frameworks/QueryKit/QueryKit.xcodeproj/project.pbxproj
@@ -87,7 +87,7 @@
17E5951E14F301DF0054EE08 /* QueryKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QueryKit.h; sourceTree = "<group>"; };
17E595F114F3058F0054EE08 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
17E5969814F307B70054EE08 /* QKSelectQueryTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QKSelectQueryTests.m; sourceTree = "<group>"; };
- 17E5969E14F307CE0054EE08 /* Tests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.octest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 17E5969E14F307CE0054EE08 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
17E5969F14F307CE0054EE08 /* Tests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Tests-Info.plist"; path = "Resources/Tests-Info.plist"; sourceTree = "<group>"; };
17F48BA615B27F6400C6455B /* QKQueryOrderBy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QKQueryOrderBy.h; sourceTree = "<group>"; };
17F48BA715B27F6400C6455B /* QKQueryOrderBy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QKQueryOrderBy.m; sourceTree = "<group>"; };
@@ -123,7 +123,7 @@
isa = PBXGroup;
children = (
8DC2EF5B0486A6940098B216 /* QueryKit.framework */,
- 17E5969E14F307CE0054EE08 /* Tests.octest */,
+ 17E5969E14F307CE0054EE08 /* Tests.xctest */,
);
name = Products;
sourceTree = "<group>";
@@ -329,8 +329,8 @@
);
name = Tests;
productName = Tests;
- productReference = 17E5969E14F307CE0054EE08 /* Tests.octest */;
- productType = "com.apple.product-type.bundle";
+ productReference = 17E5969E14F307CE0054EE08 /* Tests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
};
8DC2EF4F0486A6940098B216 /* QueryKit */ = {
isa = PBXNativeTarget;
@@ -357,7 +357,7 @@
0867D690FE84028FC02AAC07 /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 0510;
+ LastUpgradeCheck = 0720;
};
buildConfigurationList = 1DEB91B108733DA50010E9CD /* Build configuration list for PBXProject "QueryKit" */;
compatibilityVersion = "Xcode 3.2";
@@ -436,7 +436,7 @@
17E5952D14F302740054EE08 /* Distribution */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
CLANG_LINK_OBJC_RUNTIME = NO;
CLANG_STATIC_ANALYZER_MODE = deep;
CLANG_WARN_BOOL_CONVERSION = YES;
@@ -444,8 +444,11 @@
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "Source/QueryKit-Prefix.pch";
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
@@ -498,6 +501,7 @@
GCC_WARN_UNUSED_VALUE = YES;
INFOPLIST_FILE = Resources/Info.plist;
INSTALL_PATH = "@executable_path/../Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = com.sequelpro.querykit;
PRODUCT_NAME = QueryKit;
SKIP_INSTALL = YES;
WARNING_CFLAGS = "-Wmost";
@@ -511,7 +515,7 @@
ALWAYS_SEARCH_USER_PATHS = NO;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
- FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks";
+ FRAMEWORK_SEARCH_PATHS = "$(inherited)";
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_MODEL_TUNING = G5;
@@ -523,12 +527,9 @@
OTHER_LDFLAGS = (
"-framework",
Cocoa,
- "-framework",
- SenTestingKit,
);
+ PRODUCT_BUNDLE_IDENTIFIER = com.sequelpro.querykit.tests;
PRODUCT_NAME = Tests;
- TEST_AFTER_BUILD = YES;
- WRAPPER_EXTENSION = octest;
};
name = Debug;
};
@@ -539,7 +540,7 @@
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks";
+ FRAMEWORK_SEARCH_PATHS = "$(inherited)";
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_MODEL_TUNING = G5;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
@@ -549,12 +550,9 @@
OTHER_LDFLAGS = (
"-framework",
Cocoa,
- "-framework",
- SenTestingKit,
);
+ PRODUCT_BUNDLE_IDENTIFIER = com.sequelpro.querykit.tests;
PRODUCT_NAME = Tests;
- TEST_AFTER_BUILD = YES;
- WRAPPER_EXTENSION = octest;
ZERO_LINK = NO;
};
name = Release;
@@ -564,7 +562,7 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
COMBINE_HIDPI_IMAGES = YES;
- FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks";
+ FRAMEWORK_SEARCH_PATHS = "$(inherited)";
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_MODEL_TUNING = G5;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
@@ -574,12 +572,9 @@
OTHER_LDFLAGS = (
"-framework",
Cocoa,
- "-framework",
- SenTestingKit,
);
+ PRODUCT_BUNDLE_IDENTIFIER = com.sequelpro.querykit.tests;
PRODUCT_NAME = Tests;
- TEST_AFTER_BUILD = YES;
- WRAPPER_EXTENSION = octest;
};
name = Distribution;
};
@@ -623,6 +618,7 @@
GENERATE_PKGINFO_FILE = YES;
INFOPLIST_FILE = Resources/Info.plist;
INSTALL_PATH = "@executable_path/../Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = com.sequelpro.querykit;
PRODUCT_NAME = QueryKit;
SKIP_INSTALL = YES;
WARNING_CFLAGS = "-Wmost";
@@ -666,6 +662,7 @@
GCC_WARN_UNUSED_VALUE = YES;
INFOPLIST_FILE = Resources/Info.plist;
INSTALL_PATH = "@executable_path/../Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = com.sequelpro.querykit;
PRODUCT_NAME = QueryKit;
SKIP_INSTALL = YES;
WARNING_CFLAGS = "-Wmost";
@@ -676,7 +673,7 @@
1DEB91B208733DA50010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
CLANG_LINK_OBJC_RUNTIME = NO;
CLANG_STATIC_ANALYZER_MODE = deep;
CLANG_WARN_BOOL_CONVERSION = YES;
@@ -684,8 +681,12 @@
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "Source/QueryKit-Prefix.pch";
@@ -707,7 +708,7 @@
1DEB91B308733DA50010E9CD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
CLANG_LINK_OBJC_RUNTIME = NO;
CLANG_STATIC_ANALYZER_MODE = deep;
CLANG_WARN_BOOL_CONVERSION = YES;
@@ -715,8 +716,11 @@
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "Source/QueryKit-Prefix.pch";
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
diff --git a/Frameworks/QueryKit/QueryKit.xcodeproj/xcshareddata/xcschemes/QueryKit.xcscheme b/Frameworks/QueryKit/QueryKit.xcodeproj/xcshareddata/xcschemes/QueryKit.xcscheme
index fcff0831..b5c97922 100644
--- a/Frameworks/QueryKit/QueryKit.xcodeproj/xcshareddata/xcschemes/QueryKit.xcscheme
+++ b/Frameworks/QueryKit/QueryKit.xcodeproj/xcshareddata/xcschemes/QueryKit.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "0510"
+ LastUpgradeVersion = "0720"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -33,12 +33,14 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "17E5969D14F307CE0054EE08"
- BuildableName = "Tests.octest"
+ BuildableName = "Tests.xctest"
BlueprintName = "Tests"
ReferencedContainer = "container:QueryKit.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
+ <AdditionalOptions>
+ </AdditionalOptions>
</TestAction>
<LaunchAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
@@ -48,7 +50,17 @@
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
+ debugServiceExtension = "internal"
allowLocationSimulation = "YES">
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "8DC2EF4F0486A6940098B216"
+ BuildableName = "QueryKit.framework"
+ BlueprintName = "QueryKit"
+ ReferencedContainer = "container:QueryKit.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
diff --git a/Frameworks/QueryKit/Resources/Info.plist b/Frameworks/QueryKit/Resources/Info.plist
index 6c5911aa..5c5cdce8 100644
--- a/Frameworks/QueryKit/Resources/Info.plist
+++ b/Frameworks/QueryKit/Resources/Info.plist
@@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>QueryKit</string>
<key>CFBundleIdentifier</key>
- <string>com.sequelpro.querykit</string>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
diff --git a/Frameworks/QueryKit/Resources/Tests-Info.plist b/Frameworks/QueryKit/Resources/Tests-Info.plist
index add26ae7..ddbc4bf7 100644
--- a/Frameworks/QueryKit/Resources/Tests-Info.plist
+++ b/Frameworks/QueryKit/Resources/Tests-Info.plist
@@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>Tests</string>
<key>CFBundleIdentifier</key>
- <string>com.sequelpro.querykit.tests</string>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
diff --git a/Frameworks/QueryKit/Tests/QKDeleteQueryTests.h b/Frameworks/QueryKit/Tests/QKDeleteQueryTests.h
index ef0e26ca..379fdaf4 100644
--- a/Frameworks/QueryKit/Tests/QKDeleteQueryTests.h
+++ b/Frameworks/QueryKit/Tests/QKDeleteQueryTests.h
@@ -29,10 +29,10 @@
#import "QKTestCase.h"
#import <QueryKit/QueryKit.h>
-#import <SenTestingKit/SenTestingKit.h>
+#import <XCTest/XCTest.h>
@interface QKDeleteQueryTests : QKTestCase
-+ (void)addTestForDatabase:(QKQueryDatabase)database withIdentifierQuote:(NSString *)quote toTestSuite:(SenTestSuite *)testSuite;
++ (void)addTestForDatabase:(QKQueryDatabase)database withIdentifierQuote:(NSString *)quote toTestSuite:(XCTestSuite *)testSuite;
@end
diff --git a/Frameworks/QueryKit/Tests/QKDeleteQueryTests.m b/Frameworks/QueryKit/Tests/QKDeleteQueryTests.m
index 438f45dd..8862fee5 100644
--- a/Frameworks/QueryKit/Tests/QKDeleteQueryTests.m
+++ b/Frameworks/QueryKit/Tests/QKDeleteQueryTests.m
@@ -36,7 +36,7 @@
+ (id)defaultTestSuite
{
- SenTestSuite *testSuite = [[SenTestSuite alloc] initWithName:NSStringFromClass(self)];
+ XCTestSuite *testSuite = [[XCTestSuite alloc] initWithName:NSStringFromClass(self)];
[self addTestForDatabase:QKDatabaseUnknown withIdentifierQuote:EMPTY_STRING toTestSuite:testSuite];
[self addTestForDatabase:QKDatabaseMySQL withIdentifierQuote:QKMySQLIdentifierQuote toTestSuite:testSuite];
@@ -45,11 +45,11 @@
return [testSuite autorelease];
}
-+ (void)addTestForDatabase:(QKQueryDatabase)database withIdentifierQuote:(NSString *)quote toTestSuite:(SenTestSuite *)testSuite
++ (void)addTestForDatabase:(QKQueryDatabase)database withIdentifierQuote:(NSString *)quote toTestSuite:(XCTestSuite *)testSuite
{
for (NSInvocation *invocation in [self testInvocations])
{
- SenTestCase *test = [[QKDeleteQueryTests alloc] initWithInvocation:invocation database:database identifierQuote:quote];
+ XCTestCase *test = [[QKDeleteQueryTests alloc] initWithInvocation:invocation database:database identifierQuote:quote];
[testSuite addTest:test];
@@ -77,14 +77,14 @@
- (void)testDeleteQueryTypeIsCorrect
{
- STAssertTrue([[[self query] query] hasPrefix:@"DELETE"], nil);
+ XCTAssertTrue([[[self query] query] hasPrefix:@"DELETE"]);
}
- (void)testDeleteQueryFromTableIsCorrect
{
NSString *query = [NSString stringWithFormat:@"DELETE FROM %1$@%2$@%1$@", [self identifierQuote], QKTestTableName];
- STAssertTrue([[[self query] query] isEqualToString:query], nil);
+ XCTAssertTrue([[[self query] query] isEqualToString:query]);
}
- (void)testDeleteQueryFromDatabaseTableIsCorrect
@@ -93,7 +93,7 @@
NSString *query = [NSString stringWithFormat:@"DELETE FROM %1$@%2$@%1$@.%1$@%3$@%1$@", [self identifierQuote], QKTestDatabaseName, QKTestTableName];
- STAssertTrue([[[self query] query] isEqualToString:query] , nil);
+ XCTAssertTrue([[[self query] query] isEqualToString:query] );
}
- (void)testDeleteQueryWithSingleConstraintIsCorrect
@@ -102,7 +102,7 @@
NSString *query = [NSString stringWithFormat:@"DELETE FROM %1$@%2$@%1$@ WHERE %1$@%3$@%1$@ %4$@ %5$@", [self identifierQuote], QKTestTableName, QKTestFieldOne, [QKQueryUtilities stringRepresentationOfQueryOperator:QKEqualityOperator], [NSNumber numberWithUnsignedInteger:QKTestParameterOne]];
- STAssertTrue([[[self query] query] isEqualToString:query] , nil);
+ XCTAssertTrue([[[self query] query] isEqualToString:query] );
}
- (void)testDeleteQueryWithMultipleConstraintsIsCorrect
@@ -115,7 +115,7 @@
NSString *query = [NSString stringWithFormat:@"DELETE FROM %1$@%2$@%1$@ WHERE %1$@%3$@%1$@ %4$@ %5$@ AND %1$@%6$@%1$@ %7$@ '%8$@'", [self identifierQuote], QKTestTableName, QKTestFieldOne, opOne, [NSNumber numberWithUnsignedInteger:QKTestParameterOne], QKTestFieldTwo, opTwo, QKTestParameterTwo];
- STAssertTrue([[[self query] query] isEqualToString:query] , nil);
+ XCTAssertTrue([[[self query] query] isEqualToString:query] );
}
@end
diff --git a/Frameworks/QueryKit/Tests/QKQueryTests.m b/Frameworks/QueryKit/Tests/QKQueryTests.m
index 0043e607..2064fad6 100644
--- a/Frameworks/QueryKit/Tests/QKQueryTests.m
+++ b/Frameworks/QueryKit/Tests/QKQueryTests.m
@@ -30,7 +30,7 @@
#import "QKTestCase.h"
#import <QueryKit/QueryKit.h>
-#import <SenTestingKit/SenTestingKit.h>
+#import <XCTest/XCTest.h>
@interface QKQueryTests : QKTestCase
@end
@@ -68,19 +68,19 @@
{
[[self query] clear];
- STAssertNil([[self query] table], @"query table");
- STAssertNil([[self query] database], @"query database");
+ XCTAssertNil([[self query] table], @"query table");
+ XCTAssertNil([[self query] database], @"query database");
- STAssertTrue([[self query] useQuotedIdentifiers], @"query use quoted identifiers");
- STAssertTrue([[[self query] identifierQuote] isEqualToString:EMPTY_STRING], @"query identifier quote");
- STAssertTrue([[[self query] fields] count] == 0, @"query fields");
- STAssertTrue([[[self query] parameters] count] == 0, @"query parameters");
- STAssertTrue([[[self query] updateParameters] count] == 0, @"query update parameters");
- STAssertTrue([[[self query] groupByFields] count] == 0, @"query group by fields");
- STAssertTrue([[[self query] orderByFields] count] == 0, @"query order by fields");
+ XCTAssertTrue([[self query] useQuotedIdentifiers], @"query use quoted identifiers");
+ XCTAssertTrue([[[self query] identifierQuote] isEqualToString:EMPTY_STRING], @"query identifier quote");
+ XCTAssertTrue([[[self query] fields] count] == 0, @"query fields");
+ XCTAssertTrue([[[self query] parameters] count] == 0, @"query parameters");
+ XCTAssertTrue([[[self query] updateParameters] count] == 0, @"query update parameters");
+ XCTAssertTrue([[[self query] groupByFields] count] == 0, @"query group by fields");
+ XCTAssertTrue([[[self query] orderByFields] count] == 0, @"query order by fields");
- STAssertEquals([[self query] queryType], QKUnknownQuery, @"query type");
- STAssertEquals([[self query] queryDatabase], QKDatabaseUnknown, @"query database");
+ XCTAssertEqual([[self query] queryType], QKUnknownQuery, @"query type");
+ XCTAssertEqual([[self query] queryDatabase], QKDatabaseUnknown, @"query database");
}
@end
diff --git a/Frameworks/QueryKit/Tests/QKSelectQueryGroupByTests.h b/Frameworks/QueryKit/Tests/QKSelectQueryGroupByTests.h
index 9a1349d8..f7966a66 100644
--- a/Frameworks/QueryKit/Tests/QKSelectQueryGroupByTests.h
+++ b/Frameworks/QueryKit/Tests/QKSelectQueryGroupByTests.h
@@ -29,10 +29,10 @@
#import "QKTestCase.h"
#import <QueryKit/QueryKit.h>
-#import <SenTestingKit/SenTestingKit.h>
+#import <XCTest/XCTest.h>
@interface QKSelectQueryGroupByTests : QKTestCase
-+ (void)addTestForDatabase:(QKQueryDatabase)database withIdentifierQuote:(NSString *)quote toTestSuite:(SenTestSuite *)testSuite;
++ (void)addTestForDatabase:(QKQueryDatabase)database withIdentifierQuote:(NSString *)quote toTestSuite:(XCTestSuite *)testSuite;
@end
diff --git a/Frameworks/QueryKit/Tests/QKSelectQueryGroupByTests.m b/Frameworks/QueryKit/Tests/QKSelectQueryGroupByTests.m
index d8e627bc..76aa1a80 100644
--- a/Frameworks/QueryKit/Tests/QKSelectQueryGroupByTests.m
+++ b/Frameworks/QueryKit/Tests/QKSelectQueryGroupByTests.m
@@ -36,7 +36,7 @@
+ (id)defaultTestSuite
{
- SenTestSuite *testSuite = [[SenTestSuite alloc] initWithName:NSStringFromClass(self)];
+ XCTestSuite *testSuite = [[XCTestSuite alloc] initWithName:NSStringFromClass(self)];
[self addTestForDatabase:QKDatabaseUnknown withIdentifierQuote:EMPTY_STRING toTestSuite:testSuite];
[self addTestForDatabase:QKDatabaseMySQL withIdentifierQuote:QKMySQLIdentifierQuote toTestSuite:testSuite];
@@ -45,11 +45,11 @@
return [testSuite autorelease];
}
-+ (void)addTestForDatabase:(QKQueryDatabase)database withIdentifierQuote:(NSString *)quote toTestSuite:(SenTestSuite *)testSuite
++ (void)addTestForDatabase:(QKQueryDatabase)database withIdentifierQuote:(NSString *)quote toTestSuite:(XCTestSuite *)testSuite
{
for (NSInvocation *invocation in [self testInvocations])
{
- SenTestCase *test = [[QKSelectQueryGroupByTests alloc] initWithInvocation:invocation database:database identifierQuote:quote];
+ XCTestCase *test = [[QKSelectQueryGroupByTests alloc] initWithInvocation:invocation database:database identifierQuote:quote];
[testSuite addTest:test];
@@ -78,7 +78,7 @@
- (void)testSelectQueryTypeIsCorrect
{
- STAssertTrue([[[self query] query] hasPrefix:@"SELECT"], nil);
+ XCTAssertTrue([[[self query] query] hasPrefix:@"SELECT"]);
}
- (void)testSelectQueryGroupByIsCorrect
@@ -87,7 +87,7 @@
NSString *query = [NSString stringWithFormat:@"GROUP BY %1$@%2$@%1$@", [self identifierQuote], QKTestFieldOne];
- STAssertTrue([[[self query] query] hasSuffix:query], nil);
+ XCTAssertTrue([[[self query] query] hasSuffix:query]);
}
- (void)testSelectQueryGroupByMultipleFieldsIsCorrect
@@ -96,7 +96,7 @@
NSString *query = [NSString stringWithFormat:@"GROUP BY %1$@%2$@%1$@, %1$@%3$@%1$@", [self identifierQuote], QKTestFieldOne, QKTestFieldTwo];
- STAssertTrue([[[self query] query] hasSuffix:query], nil);
+ XCTAssertTrue([[[self query] query] hasSuffix:query]);
}
@end
diff --git a/Frameworks/QueryKit/Tests/QKSelectQueryOrderByTests.h b/Frameworks/QueryKit/Tests/QKSelectQueryOrderByTests.h
index efd7eb2f..ffca6929 100644
--- a/Frameworks/QueryKit/Tests/QKSelectQueryOrderByTests.h
+++ b/Frameworks/QueryKit/Tests/QKSelectQueryOrderByTests.h
@@ -29,10 +29,10 @@
#import "QKTestCase.h"
#import <QueryKit/QueryKit.h>
-#import <SenTestingKit/SenTestingKit.h>
+#import <XCTest/XCTest.h>
@interface QKSelectQueryOrderByTests : QKTestCase
-+ (void)addTestForDatabase:(QKQueryDatabase)database withIdentifierQuote:(NSString *)quote toTestSuite:(SenTestSuite *)testSuite;
++ (void)addTestForDatabase:(QKQueryDatabase)database withIdentifierQuote:(NSString *)quote toTestSuite:(XCTestSuite *)testSuite;
@end
diff --git a/Frameworks/QueryKit/Tests/QKSelectQueryOrderByTests.m b/Frameworks/QueryKit/Tests/QKSelectQueryOrderByTests.m
index b6847d11..a1be1d0c 100644
--- a/Frameworks/QueryKit/Tests/QKSelectQueryOrderByTests.m
+++ b/Frameworks/QueryKit/Tests/QKSelectQueryOrderByTests.m
@@ -36,7 +36,7 @@
+ (id)defaultTestSuite
{
- SenTestSuite *testSuite = [[SenTestSuite alloc] initWithName:NSStringFromClass(self)];
+ XCTestSuite *testSuite = [[XCTestSuite alloc] initWithName:NSStringFromClass(self)];
[self addTestForDatabase:QKDatabaseUnknown withIdentifierQuote:EMPTY_STRING toTestSuite:testSuite];
[self addTestForDatabase:QKDatabaseMySQL withIdentifierQuote:QKMySQLIdentifierQuote toTestSuite:testSuite];
@@ -45,11 +45,11 @@
return [testSuite autorelease];
}
-+ (void)addTestForDatabase:(QKQueryDatabase)database withIdentifierQuote:(NSString *)quote toTestSuite:(SenTestSuite *)testSuite
++ (void)addTestForDatabase:(QKQueryDatabase)database withIdentifierQuote:(NSString *)quote toTestSuite:(XCTestSuite *)testSuite
{
for (NSInvocation *invocation in [self testInvocations])
{
- SenTestCase *test = [[QKSelectQueryOrderByTests alloc] initWithInvocation:invocation database:database identifierQuote:quote];
+ XCTestCase *test = [[QKSelectQueryOrderByTests alloc] initWithInvocation:invocation database:database identifierQuote:quote];
[testSuite addTest:test];
@@ -78,7 +78,7 @@
- (void)testSelectQueryTypeIsCorrect
{
- STAssertTrue([[[self query] query] hasPrefix:@"SELECT"], nil);
+ XCTAssertTrue([[[self query] query] hasPrefix:@"SELECT"]);
}
- (void)testSelectQueryOrderByAscendingIsCorrect
@@ -87,7 +87,7 @@
NSString *query = [NSString stringWithFormat:@"ORDER BY %1$@%2$@%1$@ ASC", [self identifierQuote], QKTestFieldOne];
- STAssertTrue([[[self query] query] hasSuffix:query], nil);
+ XCTAssertTrue([[[self query] query] hasSuffix:query]);
}
- (void)testSelectQueryOrderByMultipleFieldsAscendingIsCorrect
@@ -97,7 +97,7 @@
NSString *query = [NSString stringWithFormat:@"ORDER BY %1$@%2$@%1$@ ASC, %1$@%3$@%1$@ ASC", [self identifierQuote], QKTestFieldOne, QKTestFieldTwo];
- STAssertTrue([[[self query] query] hasSuffix:query], nil);
+ XCTAssertTrue([[[self query] query] hasSuffix:query]);
}
- (void)testSelectQueryOrderByDescendingIsCorrect
@@ -106,7 +106,7 @@
NSString *query = [NSString stringWithFormat:@"ORDER BY %1$@%2$@%1$@ DESC", [self identifierQuote], QKTestFieldOne];
- STAssertTrue([[[self query] query] hasSuffix:query], nil);
+ XCTAssertTrue([[[self query] query] hasSuffix:query]);
}
- (void)testSelectQueryOrderByMultipleFieldsDescendingIsCorrect
@@ -116,7 +116,7 @@
NSString *query = [NSString stringWithFormat:@"ORDER BY %1$@%2$@%1$@ DESC, %1$@%3$@%1$@ DESC", [self identifierQuote], QKTestFieldOne, QKTestFieldTwo];
- STAssertTrue([[[self query] query] hasSuffix:query], nil);
+ XCTAssertTrue([[[self query] query] hasSuffix:query]);
}
@end
diff --git a/Frameworks/QueryKit/Tests/QKSelectQueryTests.h b/Frameworks/QueryKit/Tests/QKSelectQueryTests.h
index 5845ad06..43eda806 100644
--- a/Frameworks/QueryKit/Tests/QKSelectQueryTests.h
+++ b/Frameworks/QueryKit/Tests/QKSelectQueryTests.h
@@ -29,10 +29,10 @@
#import "QKTestCase.h"
#import <QueryKit/QueryKit.h>
-#import <SenTestingKit/SenTestingKit.h>
+#import <XCTest/XCTest.h>
@interface QKSelectQueryTests : QKTestCase
-+ (void)addTestForDatabase:(QKQueryDatabase)database withIdentifierQuote:(NSString *)quote toTestSuite:(SenTestSuite *)testSuite;
++ (void)addTestForDatabase:(QKQueryDatabase)database withIdentifierQuote:(NSString *)quote toTestSuite:(XCTestSuite *)testSuite;
@end
diff --git a/Frameworks/QueryKit/Tests/QKSelectQueryTests.m b/Frameworks/QueryKit/Tests/QKSelectQueryTests.m
index 0f1153c6..ec5328be 100644
--- a/Frameworks/QueryKit/Tests/QKSelectQueryTests.m
+++ b/Frameworks/QueryKit/Tests/QKSelectQueryTests.m
@@ -36,7 +36,7 @@
+ (id)defaultTestSuite
{
- SenTestSuite *testSuite = [[SenTestSuite alloc] initWithName:NSStringFromClass(self)];
+ XCTestSuite *testSuite = [[XCTestSuite alloc] initWithName:NSStringFromClass(self)];
[self addTestForDatabase:QKDatabaseUnknown withIdentifierQuote:EMPTY_STRING toTestSuite:testSuite];
[self addTestForDatabase:QKDatabaseMySQL withIdentifierQuote:QKMySQLIdentifierQuote toTestSuite:testSuite];
@@ -45,11 +45,11 @@
return [testSuite autorelease];
}
-+ (void)addTestForDatabase:(QKQueryDatabase)database withIdentifierQuote:(NSString *)quote toTestSuite:(SenTestSuite *)testSuite
++ (void)addTestForDatabase:(QKQueryDatabase)database withIdentifierQuote:(NSString *)quote toTestSuite:(XCTestSuite *)testSuite
{
for (NSInvocation *invocation in [self testInvocations])
{
- SenTestCase *test = [[QKSelectQueryTests alloc] initWithInvocation:invocation database:database identifierQuote:quote];
+ XCTestCase *test = [[QKSelectQueryTests alloc] initWithInvocation:invocation database:database identifierQuote:quote];
[testSuite addTest:test];
@@ -82,14 +82,14 @@
- (void)testSelectQueryTypeIsCorrect
{
- STAssertTrue([[[self query] query] hasPrefix:@"SELECT"], nil);
+ XCTAssertTrue([[[self query] query] hasPrefix:@"SELECT"]);
}
- (void)testSelectQueryFieldIsCorrect
{
NSString *query = [NSString stringWithFormat:@"SELECT %1$@%2$@%1$@", [self identifierQuote], QKTestFieldOne];
- STAssertTrue([[[self query] query] hasPrefix:query], nil);
+ XCTAssertTrue([[[self query] query] hasPrefix:query]);
}
- (void)testSelectQueryFromDatabaseAndTableIsCorrect
@@ -98,21 +98,21 @@
NSString *query = [NSString stringWithFormat:@"FROM %1$@%2$@%1$@.%1$@%3$@%1$@", [self identifierQuote], QKTestDatabaseName, QKTestTableName];
- STAssertTrue([[[self query] query] rangeOfString:query].location != NSNotFound, nil);
+ XCTAssertTrue([[[self query] query] rangeOfString:query].location != NSNotFound);
}
- (void)testSelectQueryMultipleFieldsAreCorrect
{
NSString *query = [NSString stringWithFormat:@"SELECT %1$@%2$@%1$@, %1$@%3$@%1$@, %1$@%4$@%1$@, %1$@%5$@%1$@", [self identifierQuote], QKTestFieldOne, QKTestFieldTwo, QKTestFieldThree, QKTestFieldFour];
- STAssertTrue([[[self query] query] hasPrefix:query], nil);
+ XCTAssertTrue([[[self query] query] hasPrefix:query]);
}
- (void)testSelectQueryConstraintsAreCorrect
{
NSString *query = [NSString stringWithFormat:@"WHERE %1$@%2$@%1$@ %3$@ %4$@", [self identifierQuote], QKTestFieldOne, [QKQueryUtilities stringRepresentationOfQueryOperator:QKEqualityOperator], [NSNumber numberWithUnsignedInteger:QKTestParameterOne]];
- STAssertTrue(([[[self query] query] rangeOfString:query].location != NSNotFound), nil);
+ XCTAssertTrue(([[[self query] query] rangeOfString:query].location != NSNotFound));
}
@end
diff --git a/Frameworks/QueryKit/Tests/QKTestCase.h b/Frameworks/QueryKit/Tests/QKTestCase.h
index 47efec04..baa4f050 100644
--- a/Frameworks/QueryKit/Tests/QKTestCase.h
+++ b/Frameworks/QueryKit/Tests/QKTestCase.h
@@ -27,9 +27,9 @@
// OTHER DEALINGS IN THE SOFTWARE.
#import <QueryKit/QueryKit.h>
-#import <SenTestingKit/SenTestingKit.h>
+#import <XCTest/XCTest.h>
-@interface QKTestCase : SenTestCase
+@interface QKTestCase : XCTestCase
{
@private
QKQuery *_query;
diff --git a/Frameworks/QueryKit/Tests/QKUpdateQueryTests.h b/Frameworks/QueryKit/Tests/QKUpdateQueryTests.h
index aede8979..7c3ea7c5 100644
--- a/Frameworks/QueryKit/Tests/QKUpdateQueryTests.h
+++ b/Frameworks/QueryKit/Tests/QKUpdateQueryTests.h
@@ -29,10 +29,10 @@
#import "QKTestCase.h"
#import <QueryKit/QueryKit.h>
-#import <SenTestingKit/SenTestingKit.h>
+#import <XCTest/XCTest.h>
@interface QKUpdateQueryTests : QKTestCase
-+ (void)addTestForDatabase:(QKQueryDatabase)database withIdentifierQuote:(NSString *)quote toTestSuite:(SenTestSuite *)testSuite;
++ (void)addTestForDatabase:(QKQueryDatabase)database withIdentifierQuote:(NSString *)quote toTestSuite:(XCTestSuite *)testSuite;
@end
diff --git a/Frameworks/QueryKit/Tests/QKUpdateQueryTests.m b/Frameworks/QueryKit/Tests/QKUpdateQueryTests.m
index 1beff6d5..039840bb 100644
--- a/Frameworks/QueryKit/Tests/QKUpdateQueryTests.m
+++ b/Frameworks/QueryKit/Tests/QKUpdateQueryTests.m
@@ -36,7 +36,7 @@
+ (id)defaultTestSuite
{
- SenTestSuite *testSuite = [[SenTestSuite alloc] initWithName:NSStringFromClass(self)];
+ XCTestSuite *testSuite = [[XCTestSuite alloc] initWithName:NSStringFromClass(self)];
[self addTestForDatabase:QKDatabaseUnknown withIdentifierQuote:EMPTY_STRING toTestSuite:testSuite];
[self addTestForDatabase:QKDatabaseMySQL withIdentifierQuote:QKMySQLIdentifierQuote toTestSuite:testSuite];
@@ -45,11 +45,11 @@
return [testSuite autorelease];
}
-+ (void)addTestForDatabase:(QKQueryDatabase)database withIdentifierQuote:(NSString *)quote toTestSuite:(SenTestSuite *)testSuite
++ (void)addTestForDatabase:(QKQueryDatabase)database withIdentifierQuote:(NSString *)quote toTestSuite:(XCTestSuite *)testSuite
{
for (NSInvocation *invocation in [self testInvocations])
{
- SenTestCase *test = [[NSClassFromString(@"QKUpdateQueryTests") alloc] initWithInvocation:invocation database:database identifierQuote:quote];
+ XCTestCase *test = [[NSClassFromString(@"QKUpdateQueryTests") alloc] initWithInvocation:invocation database:database identifierQuote:quote];
[testSuite addTest:test];
@@ -81,7 +81,7 @@
- (void)testUpdateQueryTypeIsCorrect
{
- STAssertTrue([[[self query] query] hasPrefix:@"UPDATE"], nil);
+ XCTAssertTrue([[[self query] query] hasPrefix:@"UPDATE"]);
}
- (void)testUpdateQueryUsingDatabaseAndTableIsCorrect
@@ -90,21 +90,21 @@
NSString *query = [NSString stringWithFormat:@"UPDATE %1$@%2$@%1$@.%1$@%3$@%1$@", [self identifierQuote], QKTestDatabaseName, QKTestTableName];
- STAssertTrue([[[self query] query] hasPrefix:query], nil);
+ XCTAssertTrue([[[self query] query] hasPrefix:query]);
}
- (void)testUpdateQueryFieldsAreCorrect
{
NSString *query = [NSString stringWithFormat:@"UPDATE %1$@%2$@%1$@ SET %1$@%3$@%1$@ = '%4$@', %1$@%5$@%1$@ = '%6$@'", [self identifierQuote], QKTestTableName, QKTestFieldOne, QKTestUpdateValueOne, QKTestFieldTwo, QKTestUpdateValueTwo];
- STAssertTrue([[[self query] query] hasPrefix:query], nil);
+ XCTAssertTrue([[[self query] query] hasPrefix:query]);
}
- (void)testUpdateQueryConstraintIsCorrect
{
NSString *query = [NSString stringWithFormat:@"WHERE %1$@%2$@%1$@ %3$@ %4$@", [self identifierQuote], QKTestFieldOne, [QKQueryUtilities stringRepresentationOfQueryOperator:QKEqualityOperator], [NSNumber numberWithUnsignedInteger:QKTestParameterOne]];
- STAssertTrue(([[[self query] query] rangeOfString:query].location != NSNotFound), nil);
+ XCTAssertTrue(([[[self query] query] rangeOfString:query].location != NSNotFound));
}
@end
diff --git a/Frameworks/SPMySQLFramework/MySQL Client Libraries/include/mysql_com.h b/Frameworks/SPMySQLFramework/MySQL Client Libraries/include/mysql_com.h
index f2345be6..8a8c019d 100644
--- a/Frameworks/SPMySQLFramework/MySQL Client Libraries/include/mysql_com.h
+++ b/Frameworks/SPMySQLFramework/MySQL Client Libraries/include/mysql_com.h
@@ -348,7 +348,11 @@ enum enum_field_types { MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY,
MYSQL_TYPE_DATETIME, MYSQL_TYPE_YEAR,
MYSQL_TYPE_NEWDATE, MYSQL_TYPE_VARCHAR,
MYSQL_TYPE_BIT,
- MYSQL_TYPE_NEWDECIMAL=246,
+ MYSQL_TYPE_TIMESTAMP2,
+ MYSQL_TYPE_DATETIME2,
+ MYSQL_TYPE_TIME2,
+ MYSQL_TYPE_JSON=245,
+ MYSQL_TYPE_NEWDECIMAL=246,
MYSQL_TYPE_ENUM=247,
MYSQL_TYPE_SET=248,
MYSQL_TYPE_TINY_BLOB=249,
diff --git a/Frameworks/SPMySQLFramework/Resources/Info.plist b/Frameworks/SPMySQLFramework/Resources/Info.plist
index 84b64d04..0932b287 100644
--- a/Frameworks/SPMySQLFramework/Resources/Info.plist
+++ b/Frameworks/SPMySQLFramework/Resources/Info.plist
@@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>SPMySQL</string>
<key>CFBundleIdentifier</key>
- <string>com.sequelpro.spmysql</string>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
diff --git a/Frameworks/SPMySQLFramework/SPMySQL Unit Tests/DataConversion_Tests.m b/Frameworks/SPMySQLFramework/SPMySQL Unit Tests/DataConversion_Tests.m
new file mode 100644
index 00000000..b8256a5c
--- /dev/null
+++ b/Frameworks/SPMySQLFramework/SPMySQL Unit Tests/DataConversion_Tests.m
@@ -0,0 +1,77 @@
+//
+// DataConversion_Tests.m
+// SPMySQLFramework
+//
+// Created by Max Lohrmann on 01.10.15.
+// Copyright (c) 2015 Max Lohrmann. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+// More info at <https://github.com/sequelpro/sequelpro>
+
+#import <Cocoa/Cocoa.h>
+#import <XCTest/XCTest.h>
+
+// this function is inaccessible outside of unit tests
+extern NSString * _bitStringWithBytes(const char *bytes, NSUInteger length, NSUInteger padLength);
+
+@interface DataConversion_Tests : XCTestCase
+
+- (void)test_bitStringWithBytes;
+
+@end
+
+@implementation DataConversion_Tests
+
+- (void)test_bitStringWithBytes
+{
+ // BIT(1)
+ {
+ const char y = '\1';
+ const char n = '\0';
+ XCTAssertEqualObjects(_bitStringWithBytes(&y,sizeof(y),1), @"1");
+ XCTAssertEqualObjects(_bitStringWithBytes(&n,sizeof(n),1), @"0");
+ }
+ // BIT(3)
+ {
+ const char input[] = {5};
+ NSUInteger bitSize = 3;
+ NSString *res = _bitStringWithBytes(input,sizeof(input),bitSize);
+ XCTAssertEqualObjects(res, @"101");
+ }
+ // BIT(16)
+ {
+ const char input[] = {0xcc,0xf0};
+ NSUInteger bitSize = 16;
+ NSString *res = _bitStringWithBytes(input,sizeof(input),bitSize);
+ XCTAssertEqualObjects(res, @"1100110011110000");
+ }
+ // BIT(20)
+ {
+ const char input[] = {0x0f,0xcc,0xf0};
+ NSUInteger bitSize = 20;
+ NSString *res = _bitStringWithBytes(input,sizeof(input),bitSize);
+ XCTAssertEqualObjects(res, @"11111100110011110000");
+ }
+}
+
+@end
diff --git a/Frameworks/SPMySQLFramework/SPMySQL Unit Tests/Info.plist b/Frameworks/SPMySQLFramework/SPMySQL Unit Tests/Info.plist
new file mode 100644
index 00000000..ba72822e
--- /dev/null
+++ b/Frameworks/SPMySQLFramework/SPMySQL Unit Tests/Info.plist
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+</dict>
+</plist>
diff --git a/Frameworks/SPMySQLFramework/SPMySQL Unit Tests/SPMySQLStringAdditions_Tests.m b/Frameworks/SPMySQLFramework/SPMySQL Unit Tests/SPMySQLStringAdditions_Tests.m
new file mode 100644
index 00000000..cc1f44dd
--- /dev/null
+++ b/Frameworks/SPMySQLFramework/SPMySQL Unit Tests/SPMySQLStringAdditions_Tests.m
@@ -0,0 +1,89 @@
+//
+// SPMySQLStringAdditions_Tests.m
+// SPMySQLFramework
+//
+// Created by Max Lohrmann on 04.10.15.
+//
+//
+
+#import <Cocoa/Cocoa.h>
+#import <XCTest/XCTest.h>
+#import <SPMySQL/SPMySQL.h>
+
+@interface SPMySQLStringAdditions_Tests : XCTestCase
+
+- (void)test_mySQLBacktickQuotedString;
+- (void)test_mySQLTickQuotedString;
+- (void)test_stringForDataBytesLengthEncoding;
+
+@end
+
+@implementation SPMySQLStringAdditions_Tests
+
+- (void)test_mySQLBacktickQuotedString
+{
+ XCTAssertEqualObjects([@"" mySQLBacktickQuotedString], @"``",@"empty string");
+
+ XCTAssertEqualObjects([@"tbl1" mySQLBacktickQuotedString], @"`tbl1`", @"regular string");
+
+ XCTAssertEqualObjects([@"tbl`1" mySQLBacktickQuotedString], @"`tbl``1`",@"string with control character");
+
+ XCTAssertEqualObjects([@"tbl``" mySQLBacktickQuotedString], @"`tbl`````",@"string with escaped control character at end");
+}
+
+- (void)test_mySQLTickQuotedString
+{
+ XCTAssertEqualObjects([@"" mySQLTickQuotedString], @"''",@"empty string");
+
+ XCTAssertEqualObjects([@"tbl1" mySQLTickQuotedString], @"'tbl1'", @"regular string");
+
+ XCTAssertEqualObjects([@"tbl'1" mySQLTickQuotedString], @"'tbl''1'",@"string with control character");
+
+ XCTAssertEqualObjects([@"tbl''" mySQLTickQuotedString], @"'tbl'''''",@"string with escaped control character at end");
+}
+
+- (void)test_stringForDataBytesLengthEncoding
+{
+ {
+ const char chr = '\0';
+ NSString *conv = [NSString stringForDataBytes:&chr length:0 encoding:NSISOLatin1StringEncoding];
+ XCTAssertEqualObjects(conv, @"",@"empty string test");
+ }
+ {
+ const char *cstr = "an ASCII C string";
+ NSString *conv = [NSString stringForDataBytes:cstr length:strlen(cstr) encoding:NSASCIIStringEncoding];
+ XCTAssertEqualObjects(conv, @"an ASCII C string", @"simple ASCII string test");
+ }
+ {
+ // the euro sign is the tricky part
+ // ISO-8859-1 (aka Latin1): not supported, codepoint 0x80 is not in use
+ // ISO-8859-1 + ISO/IEC 6429: not supported, codepoint 0x80 is PAD control character
+ // ISO-8859-15 (aka Latin9): € is at 0xA4, codepoint 0x80 is PAD control character
+ // Windows cp1252 (aka latin1 in mysql): € is at 0x80, codepoint 0xA4 is "¤"
+ const char cstr[] = {'\xE4','-','\xDF','-','\x80','\0'};
+ NSString *conv = [NSString stringForDataBytes:cstr length:strlen(cstr) encoding:NSWindowsCP1252StringEncoding];
+ XCTAssertEqualObjects(conv, @"ä-ß-€",@"handling of cp1252 special characters");
+
+ unsigned char latin9 = 0xA4;
+ NSString *conv2 = [NSString stringForDataBytes:&latin9 length:1 encoding:CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingISOLatin9)];
+ XCTAssertEqualObjects(conv2, @"€",@"handling of iso-8859-15 special characters");
+ }
+ {
+ const char *cstr = "エスキューエル";
+ NSString *conv = [NSString stringForDataBytes:cstr length:strlen(cstr) encoding:NSUTF8StringEncoding];
+ XCTAssertEqualObjects(conv, @"エスキューエル",@"handling of valid utf-8 string");
+ }
+ {
+ // this is a test for a certain mysql issue:
+ // mysql limits field names to 255 characters and will even cut multibyte chars in the middle,
+ // if neccesary. This will create invalid characters which cause NSString
+ // to fail and return nil on the whole string. Since we know that, we can
+ // at least try to return something.
+ char cstr[] = {'\xE3','\x82','\xA8','\xE3','\x82','\xB9','\xE3','\x82','\xAD','\xE3','\x83','\xA5','\xE3','\x83','\xBC','\xE3','\x82','\xA8','\xE3','\x83','\xAB','\0'}; // エスキューエル
+ cstr[strlen(cstr)-2] = '\0'; //simulate cutting off the string
+ NSString *conv = [NSString stringForDataBytes:cstr length:strlen(cstr) encoding:NSUTF8StringEncoding];
+ XCTAssertNotNil(conv, @"handling of invalid utf8 sequences");
+ }
+}
+
+@end
diff --git a/Frameworks/SPMySQLFramework/SPMySQLDataTypes.h b/Frameworks/SPMySQLFramework/SPMySQLDataTypes.h
index def1e988..31acf6b8 100644
--- a/Frameworks/SPMySQLFramework/SPMySQLDataTypes.h
+++ b/Frameworks/SPMySQLFramework/SPMySQLDataTypes.h
@@ -72,3 +72,4 @@ extern NSString *SPMySQLMultiPointType;
extern NSString *SPMySQLMultiLineStringType;
extern NSString *SPMySQLMultiPolygonType;
extern NSString *SPMySQLGeometryCollectionType;
+extern NSString *SPMySQLJsonType;
diff --git a/Frameworks/SPMySQLFramework/SPMySQLDataTypes.m b/Frameworks/SPMySQLFramework/SPMySQLDataTypes.m
index 06708f1b..d7f54c0e 100644
--- a/Frameworks/SPMySQLFramework/SPMySQLDataTypes.m
+++ b/Frameworks/SPMySQLFramework/SPMySQLDataTypes.m
@@ -74,3 +74,4 @@ NSString *SPMySQLMultiPointType = @"MULTIPOINT";
NSString *SPMySQLMultiLineStringType = @"MULTILINESTRING";
NSString *SPMySQLMultiPolygonType = @"MULTIPOLYGON";
NSString *SPMySQLGeometryCollectionType = @"GEOMETRYCOLLECTION";
+NSString *SPMySQLJsonType = @"JSON";
diff --git a/Frameworks/SPMySQLFramework/SPMySQLFramework.xcodeproj/project.pbxproj b/Frameworks/SPMySQLFramework/SPMySQLFramework.xcodeproj/project.pbxproj
index 9acf9417..778b97f9 100644
--- a/Frameworks/SPMySQLFramework/SPMySQLFramework.xcodeproj/project.pbxproj
+++ b/Frameworks/SPMySQLFramework/SPMySQLFramework.xcodeproj/project.pbxproj
@@ -9,6 +9,9 @@
/* Begin PBXBuildFile section */
17E3A57B1885A286009CF372 /* SPMySQLDataTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 17E3A5791885A286009CF372 /* SPMySQLDataTypes.h */; settings = {ATTRIBUTES = (Public, ); }; };
17E3A57C1885A286009CF372 /* SPMySQLDataTypes.m in Sources */ = {isa = PBXBuildFile; fileRef = 17E3A57A1885A286009CF372 /* SPMySQLDataTypes.m */; };
+ 507FF1E51BC0D82300104523 /* DataConversion_Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 507FF1811BC0C64100104523 /* DataConversion_Tests.m */; };
+ 507FF23B1BC0E8CA00104523 /* SPMySQL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* SPMySQL.framework */; };
+ 507FF23D1BC157B500104523 /* SPMySQLStringAdditions_Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 507FF23C1BC157B500104523 /* SPMySQLStringAdditions_Tests.m */; };
580A331E14D75CF7000D6933 /* SPMySQLGeometryData.h in Headers */ = {isa = PBXBuildFile; fileRef = 580A331C14D75CF7000D6933 /* SPMySQLGeometryData.h */; settings = {ATTRIBUTES = (Public, ); }; };
580A331F14D75CF7000D6933 /* SPMySQLGeometryData.m in Sources */ = {isa = PBXBuildFile; fileRef = 580A331D14D75CF7000D6933 /* SPMySQLGeometryData.m */; };
583C734A17A489CC0056B284 /* SPMySQLStreamingResultStoreDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 583C734917A489CC0056B284 /* SPMySQLStreamingResultStoreDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -75,6 +78,16 @@
8DC2EF570486A6940098B216 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */; };
/* End PBXBuildFile section */
+/* Begin PBXContainerItemProxy section */
+ 507FF2391BC0E8AF00104523 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 8DC2EF4F0486A6940098B216;
+ remoteInfo = SPMySQL.framework;
+ };
+/* End PBXContainerItemProxy section */
+
/* Begin PBXFileReference section */
0867D69BFE84028FC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
0867D6A5FE840307C02AAC07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
@@ -83,6 +96,10 @@
17E3A5791885A286009CF372 /* SPMySQLDataTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPMySQLDataTypes.h; sourceTree = "<group>"; };
17E3A57A1885A286009CF372 /* SPMySQLDataTypes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPMySQLDataTypes.m; sourceTree = "<group>"; };
32DBCF5E0370ADEE00C91783 /* SPMySQLFramework_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SPMySQLFramework_Prefix.pch; path = Source/SPMySQLFramework_Prefix.pch; sourceTree = "<group>"; };
+ 507FF1811BC0C64100104523 /* DataConversion_Tests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DataConversion_Tests.m; sourceTree = "<group>"; };
+ 507FF1D51BC0D7D300104523 /* SPMySQL Unit Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SPMySQL Unit Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 507FF1D81BC0D7D300104523 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ 507FF23C1BC157B500104523 /* SPMySQLStringAdditions_Tests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPMySQLStringAdditions_Tests.m; sourceTree = "<group>"; };
580A331C14D75CF7000D6933 /* SPMySQLGeometryData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SPMySQLGeometryData.h; path = Source/SPMySQLGeometryData.h; sourceTree = "<group>"; };
580A331D14D75CF7000D6933 /* SPMySQLGeometryData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SPMySQLGeometryData.m; path = Source/SPMySQLGeometryData.m; sourceTree = "<group>"; };
583C734917A489CC0056B284 /* SPMySQLStreamingResultStoreDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SPMySQLStreamingResultStoreDelegate.h; path = Source/SPMySQLStreamingResultStoreDelegate.h; sourceTree = "<group>"; };
@@ -153,6 +170,14 @@
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
+ 507FF1D21BC0D7D300104523 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 507FF23B1BC0E8CA00104523 /* SPMySQL.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
8DC2EF560486A6940098B216 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -171,6 +196,7 @@
isa = PBXGroup;
children = (
8DC2EF5B0486A6940098B216 /* SPMySQL.framework */,
+ 507FF1D51BC0D7D300104523 /* SPMySQL Unit Tests.xctest */,
);
name = Products;
sourceTree = "<group>";
@@ -184,6 +210,7 @@
08FB77AEFE84172EC02AAC07 /* Classes */,
58C009D214E31D1300AC489A /* Category Additions */,
32C88DFF0371C24200C91783 /* Other Sources */,
+ 507FF1801BC0C64100104523 /* Unit Tests */,
089C1665FE841158C02AAC07 /* Resources */,
58428DF514BA5A03000F8438 /* Scripts */,
0867D69AFE84028FC02AAC07 /* Linked Frameworks */,
@@ -252,6 +279,17 @@
name = "Other Sources";
sourceTree = "<group>";
};
+ 507FF1801BC0C64100104523 /* Unit Tests */ = {
+ isa = PBXGroup;
+ children = (
+ 507FF1D81BC0D7D300104523 /* Info.plist */,
+ 507FF1811BC0C64100104523 /* DataConversion_Tests.m */,
+ 507FF23C1BC157B500104523 /* SPMySQLStringAdditions_Tests.m */,
+ );
+ name = "Unit Tests";
+ path = "SPMySQL Unit Tests";
+ sourceTree = "<group>";
+ };
580A331B14D75CCF000D6933 /* Result types */ = {
isa = PBXGroup;
children = (
@@ -419,6 +457,24 @@
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
+ 507FF1D41BC0D7D300104523 /* SPMySQL Unit Tests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 507FF1DE1BC0D7D300104523 /* Build configuration list for PBXNativeTarget "SPMySQL Unit Tests" */;
+ buildPhases = (
+ 507FF1D11BC0D7D300104523 /* Sources */,
+ 507FF1D21BC0D7D300104523 /* Frameworks */,
+ 507FF1D31BC0D7D300104523 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 507FF23A1BC0E8AF00104523 /* PBXTargetDependency */,
+ );
+ name = "SPMySQL Unit Tests";
+ productName = "SPMySQL Unit Tests";
+ productReference = 507FF1D51BC0D7D300104523 /* SPMySQL Unit Tests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
8DC2EF4F0486A6940098B216 /* SPMySQL.framework */ = {
isa = PBXNativeTarget;
buildConfigurationList = 1DEB91AD08733DA50010E9CD /* Build configuration list for PBXNativeTarget "SPMySQL.framework" */;
@@ -444,7 +500,12 @@
0867D690FE84028FC02AAC07 /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 0510;
+ LastUpgradeCheck = 0720;
+ TargetAttributes = {
+ 507FF1D41BC0D7D300104523 = {
+ CreatedOnToolsVersion = 6.2;
+ };
+ };
};
buildConfigurationList = 1DEB91B108733DA50010E9CD /* Build configuration list for PBXProject "SPMySQLFramework" */;
compatibilityVersion = "Xcode 3.2";
@@ -462,11 +523,19 @@
projectRoot = "";
targets = (
8DC2EF4F0486A6940098B216 /* SPMySQL.framework */,
+ 507FF1D41BC0D7D300104523 /* SPMySQL Unit Tests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
+ 507FF1D31BC0D7D300104523 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
8DC2EF520486A6940098B216 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@@ -478,6 +547,15 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
+ 507FF1D11BC0D7D300104523 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 507FF23D1BC157B500104523 /* SPMySQLStringAdditions_Tests.m in Sources */,
+ 507FF1E51BC0D82300104523 /* DataConversion_Tests.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
8DC2EF540486A6940098B216 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -510,6 +588,14 @@
};
/* End PBXSourcesBuildPhase section */
+/* Begin PBXTargetDependency section */
+ 507FF23A1BC0E8AF00104523 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 8DC2EF4F0486A6940098B216 /* SPMySQL.framework */;
+ targetProxy = 507FF2391BC0E8AF00104523 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
/* Begin PBXVariantGroup section */
089C1666FE841158C02AAC07 /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
@@ -532,7 +618,6 @@
DYLIB_CURRENT_VERSION = 1;
FRAMEWORK_VERSION = A;
GCC_DYNAMIC_NO_PIC = NO;
- GCC_MODEL_TUNING = G5;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = Source/SPMySQLFramework_Prefix.pch;
GENERATE_PKGINFO_FILE = YES;
@@ -543,6 +628,7 @@
"$(inherited)",
"\"$(SRCROOT)/MySQL Client Libraries/lib\"",
);
+ PRODUCT_BUNDLE_IDENTIFIER = com.sequelpro.spmysql;
PRODUCT_NAME = SPMySQL;
SKIP_INSTALL = YES;
WRAPPER_EXTENSION = framework;
@@ -559,7 +645,6 @@
DYLIB_CURRENT_VERSION = 1;
FRAMEWORK_VERSION = A;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
- GCC_MODEL_TUNING = G5;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = Source/SPMySQLFramework_Prefix.pch;
INFOPLIST_FILE = Resources/Info.plist;
@@ -568,6 +653,7 @@
"$(inherited)",
"\"$(SRCROOT)/MySQL Client Libraries/lib\"",
);
+ PRODUCT_BUNDLE_IDENTIFIER = com.sequelpro.spmysql;
PRODUCT_NAME = SPMySQL;
SKIP_INSTALL = YES;
WRAPPER_EXTENSION = framework;
@@ -585,6 +671,7 @@
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
@@ -644,6 +731,203 @@
};
name = Release;
};
+ 507FF1DF1BC0D7D300104523 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = NO;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ COMBINE_HIDPI_IMAGES = YES;
+ COPY_PHASE_STRIP = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(DEVELOPER_FRAMEWORKS_DIR)",
+ "$(inherited)",
+ );
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ INFOPLIST_FILE = "SPMySQL Unit Tests/Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
+ MACOSX_DEPLOYMENT_TARGET = 10.9;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = "com.sequelpro.spmysql-unittests";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 507FF1E11BC0D7D300104523 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = NO;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ COMBINE_HIDPI_IMAGES = YES;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(DEVELOPER_FRAMEWORKS_DIR)",
+ "$(inherited)",
+ );
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ INFOPLIST_FILE = "SPMySQL Unit Tests/Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
+ MACOSX_DEPLOYMENT_TARGET = 10.9;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_BUNDLE_IDENTIFIER = "com.sequelpro.spmysql-unittests";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 507FF1E21BC0D7D300104523 /* Distribution */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = NO;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ COMBINE_HIDPI_IMAGES = YES;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(DEVELOPER_FRAMEWORKS_DIR)",
+ "$(inherited)",
+ );
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ INFOPLIST_FILE = "SPMySQL Unit Tests/Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
+ MACOSX_DEPLOYMENT_TARGET = 10.9;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_BUNDLE_IDENTIFIER = "com.sequelpro.spmysql-unittests";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Distribution;
+ };
+ 507FF2361BC0E0A800104523 /* Unit Testing */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ CLANG_LINK_OBJC_RUNTIME = NO;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = "";
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
+ GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
+ GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
+ GCC_WARN_MISSING_PARENTHESES = YES;
+ GCC_WARN_SHADOW = YES;
+ GCC_WARN_SIGN_COMPARE = YES;
+ GCC_WARN_STRICT_SELECTOR_MATCH = YES;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ MACH_O_TYPE = mh_dylib;
+ MACOSX_DEPLOYMENT_TARGET = 10.6;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = macosx;
+ VALID_ARCHS = "i386 x86_64";
+ };
+ name = "Unit Testing";
+ };
+ 507FF2371BC0E0A800104523 /* Unit Testing */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COMBINE_HIDPI_IMAGES = YES;
+ DEAD_CODE_STRIPPING = YES;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ FRAMEWORK_VERSION = A;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = Source/SPMySQLFramework_Prefix.pch;
+ GCC_PREPROCESSOR_DEFINITIONS = SPMYSQL_FOR_UNIT_TESTING;
+ GENERATE_PKGINFO_FILE = YES;
+ INFOPLIST_FILE = Resources/Info.plist;
+ INSTALL_PATH = "@executable_path/../Frameworks";
+ LD_DYLIB_INSTALL_NAME = "$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)";
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "\"$(SRCROOT)/MySQL Client Libraries/lib\"",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.sequelpro.spmysql;
+ PRODUCT_NAME = SPMySQL;
+ SKIP_INSTALL = YES;
+ WRAPPER_EXTENSION = framework;
+ };
+ name = "Unit Testing";
+ };
+ 507FF2381BC0E0A800104523 /* Unit Testing */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = NO;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ COMBINE_HIDPI_IMAGES = YES;
+ COPY_PHASE_STRIP = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(DEVELOPER_FRAMEWORKS_DIR)",
+ "$(inherited)",
+ );
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ INFOPLIST_FILE = "SPMySQL Unit Tests/Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
+ MACOSX_DEPLOYMENT_TARGET = 10.9;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = "com.sequelpro.spmysql-unittests";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = "Unit Testing";
+ };
586AA55214F5D599007F82BF /* Distribution */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -688,7 +972,6 @@
DYLIB_CURRENT_VERSION = 1;
FRAMEWORK_VERSION = A;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
- GCC_MODEL_TUNING = G5;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = Source/SPMySQLFramework_Prefix.pch;
INFOPLIST_FILE = Resources/Info.plist;
@@ -697,6 +980,7 @@
"$(inherited)",
"\"$(SRCROOT)/MySQL Client Libraries/lib\"",
);
+ PRODUCT_BUNDLE_IDENTIFIER = com.sequelpro.spmysql;
PRODUCT_NAME = SPMySQL;
SKIP_INSTALL = YES;
WRAPPER_EXTENSION = framework;
@@ -710,6 +994,7 @@
isa = XCConfigurationList;
buildConfigurations = (
1DEB91AE08733DA50010E9CD /* Debug */,
+ 507FF2371BC0E0A800104523 /* Unit Testing */,
1DEB91AF08733DA50010E9CD /* Release */,
586AA55314F5D599007F82BF /* Distribution */,
);
@@ -720,12 +1005,24 @@
isa = XCConfigurationList;
buildConfigurations = (
1DEB91B208733DA50010E9CD /* Debug */,
+ 507FF2361BC0E0A800104523 /* Unit Testing */,
1DEB91B308733DA50010E9CD /* Release */,
586AA55214F5D599007F82BF /* Distribution */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
+ 507FF1DE1BC0D7D300104523 /* Build configuration list for PBXNativeTarget "SPMySQL Unit Tests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 507FF1DF1BC0D7D300104523 /* Debug */,
+ 507FF2381BC0E0A800104523 /* Unit Testing */,
+ 507FF1E11BC0D7D300104523 /* Release */,
+ 507FF1E21BC0D7D300104523 /* Distribution */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
/* End XCConfigurationList section */
};
rootObject = 0867D690FE84028FC02AAC07 /* Project object */;
diff --git a/Frameworks/SPMySQLFramework/SPMySQLFramework.xcodeproj/xcshareddata/xcschemes/SPMySQL.framework.xcscheme b/Frameworks/SPMySQLFramework/SPMySQLFramework.xcodeproj/xcshareddata/xcschemes/SPMySQL.framework.xcscheme
new file mode 100644
index 00000000..6b85f25b
--- /dev/null
+++ b/Frameworks/SPMySQLFramework/SPMySQLFramework.xcodeproj/xcshareddata/xcschemes/SPMySQL.framework.xcscheme
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ LastUpgradeVersion = "0720"
+ version = "1.3">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "8DC2EF4F0486A6940098B216"
+ BuildableName = "SPMySQL.framework"
+ BlueprintName = "SPMySQL.framework"
+ ReferencedContainer = "container:SPMySQLFramework.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ buildConfiguration = "Unit Testing"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES">
+ <Testables>
+ <TestableReference
+ skipped = "NO">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "507FF1D41BC0D7D300104523"
+ BuildableName = "SPMySQL Unit Tests.xctest"
+ BlueprintName = "SPMySQL Unit Tests"
+ ReferencedContainer = "container:SPMySQLFramework.xcodeproj">
+ </BuildableReference>
+ </TestableReference>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "8DC2EF4F0486A6940098B216"
+ BuildableName = "SPMySQL.framework"
+ BlueprintName = "SPMySQL.framework"
+ ReferencedContainer = "container:SPMySQLFramework.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </TestAction>
+ <LaunchAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ debugServiceExtension = "internal"
+ allowLocationSimulation = "YES">
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "8DC2EF4F0486A6940098B216"
+ BuildableName = "SPMySQL.framework"
+ BlueprintName = "SPMySQL.framework"
+ ReferencedContainer = "container:SPMySQLFramework.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ buildConfiguration = "Release"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ debugDocumentVersioning = "YES">
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "8DC2EF4F0486A6940098B216"
+ BuildableName = "SPMySQL.framework"
+ BlueprintName = "SPMySQL.framework"
+ ReferencedContainer = "container:SPMySQLFramework.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Debug">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+</Scheme>
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQL Private APIs.h b/Frameworks/SPMySQLFramework/Source/SPMySQL Private APIs.h
index 2419d7a9..1e2a8c14 100644
--- a/Frameworks/SPMySQLFramework/Source/SPMySQL Private APIs.h
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQL Private APIs.h
@@ -82,6 +82,7 @@
@interface SPMySQLConnection (Querying_and_Preparation_Private_API)
- (void)_flushMultipleResultSets;
+- (void)_updateLastErrorInfos;
- (void)_updateLastErrorMessage:(NSString *)theErrorMessage;
- (void)_updateLastErrorID:(NSUInteger)theErrorID;
- (void)_updateLastSqlstate:(NSString *)theSqlstate;
@@ -99,12 +100,7 @@
@end
// SPMySQLResult Data Conversion Private API
-@interface SPMySQLResult (Data_Conversion_Private_API)
-
-+ (void)_initializeDataConversion;
-- (id)_getObjectFromBytes:(char *)bytes ofLength:(NSUInteger)length fieldDefinitionIndex:(NSUInteger)fieldIndex previewLength:(NSUInteger)previewLength;
-
-@end
+#import "Data Conversion.h"
/**
* Set up a static function to allow fast calling of SPMySQLResult data conversion with cached selectors
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Encoding.m b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Encoding.m
index fb949679..76f323bc 100644
--- a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Encoding.m
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Encoding.m
@@ -213,7 +213,7 @@
if (!strcmp(mysqlCharset, "utf8")) {
return NSUTF8StringEncoding;
} else if (!strcmp(mysqlCharset, "latin1")) {
- return NSISOLatin1StringEncoding;
+ return NSWindowsCP1252StringEncoding; // Warning: This is NOT the same as ISO-8859-1 (aka "ISO Latin 1")
} else if (!strcmp(mysqlCharset, "ascii")) {
return NSASCIIStringEncoding;
@@ -289,7 +289,7 @@
} else if (!strcmp(mysqlCharset, "dos")) {
return CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingDOSLatin1);
} else if (!strcmp(mysqlCharset, "german1")) {
- return NSISOLatin1StringEncoding;
+ return NSWindowsCP1252StringEncoding;
} else if (!strcmp(mysqlCharset, "usa7")) {
return NSASCIIStringEncoding;
} else if (!strcmp(mysqlCharset, "danish")) {
@@ -313,7 +313,7 @@
} else if (!strcmp(mysqlCharset, "croat")) {
return NSISOLatin2StringEncoding;
} else if (!strcmp(mysqlCharset, "latin1_de")) {
- return NSISOLatin1StringEncoding;
+ return NSWindowsCP1252StringEncoding;
}
/**
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Ping & KeepAlive.h b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Ping & KeepAlive.h
index cff8d43b..a3f34817 100644
--- a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Ping & KeepAlive.h
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Ping & KeepAlive.h
@@ -32,8 +32,8 @@
typedef struct {
MYSQL *mySQLConnection;
- BOOL *keepAlivePingActivePointer;
- BOOL *keepAliveLastPingSuccessPointer;
+ volatile BOOL *keepAlivePingThreadActivePointer;
+ volatile BOOL *keepAliveLastPingSuccessPointer;
} SPMySQLConnectionPingDetails;
@interface SPMySQLConnection (Ping_and_KeepAlive)
@@ -51,6 +51,6 @@ void _forceThreadExit(int signalNumber);
void _pingThreadCleanup(void *pingDetails);
// Cancellation
-- (void)_cancelKeepAlives;
+- (BOOL)_cancelKeepAlives;
@end
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Ping & KeepAlive.m b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Ping & KeepAlive.m
index 7443a67e..7940b483 100644
--- a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Ping & KeepAlive.m
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Ping & KeepAlive.m
@@ -80,8 +80,12 @@
*/
- (void)_threadedKeepAlive
{
+ if(keepAliveThread) {
+ NSLog(@"warning: overwriting existing keepAliveThread: %@, results may be unpredictable!",keepAliveThread);
+ }
+
keepAliveThread = [NSThread currentThread];
- [keepAliveThread setName:@"SPMySQL connection keepalive thread"];
+ [keepAliveThread setName:@"SPMySQL connection keepalive monitor thread"];
// If the maximum number of ping failures has been reached, determine whether to reconnect.
if (keepAliveLastPingBlocked || keepAlivePingFailures >= 3) {
@@ -90,16 +94,15 @@
// attempt a single reconnection in the background
if (_elapsedSecondsSinceAbsoluteTime(lastConnectionUsedTime) < 60 * 15) {
[self _reconnectAfterBackgroundConnectionLoss];
-
+ }
// Otherwise set the state to connection lost for automatic reconnect on
// next use.
- } else {
+ else {
state = SPMySQLConnectionLostInBackground;
}
// Return as no further ping action required this cycle.
- keepAliveThread = nil;
- return;
+ goto end_cleanup;
}
// Otherwise, perform a background ping.
@@ -109,6 +112,7 @@
} else {
keepAlivePingFailures++;
}
+end_cleanup:
keepAliveThread = nil;
}
@@ -135,8 +139,13 @@
// Set up a query lock
[self _lockConnection];
+ //we might find ourselves at the losing end of a contest with -[self _disconnect]
+ if(!mySQLConnection) {
+ [self _unlockConnection];
+ return NO;
+ }
- keepAliveLastPingSuccess = NO;
+ volatile BOOL keepAliveLastPingSuccess = NO;
keepAliveLastPingBlocked = NO;
keepAlivePingThreadActive = YES;
@@ -148,12 +157,14 @@
SPMySQLConnectionPingDetails *pingDetails = malloc(sizeof(SPMySQLConnectionPingDetails));
pingDetails->mySQLConnection = mySQLConnection;
pingDetails->keepAliveLastPingSuccessPointer = &keepAliveLastPingSuccess;
- pingDetails->keepAlivePingActivePointer = &keepAlivePingThreadActive;
+ pingDetails->keepAlivePingThreadActivePointer = &keepAlivePingThreadActive;
// Create a pthread for the ping
+ pthread_t keepAlivePingThread_t;
+
pthread_attr_t attr;
pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_create(&keepAlivePingThread_t, &attr, (void *)&_backgroundPingTask, pingDetails);
// Record the ping start time
@@ -166,7 +177,7 @@
// If the ping timeout has been exceeded, or the ping thread has been
// cancelled, force a timeout; double-check that the thread is still active.
- if (([keepAliveThread isCancelled] || pingElapsedTime > pingTimeout)
+ if (([[NSThread currentThread] isCancelled] || pingElapsedTime > pingTimeout)
&& keepAlivePingThreadActive
&& !threadCancelled)
{
@@ -182,6 +193,9 @@
keepAliveLastPingBlocked = YES;
}
} while (keepAlivePingThreadActive);
+
+ //wait for thread to go away, otherwise our free() below might run before _pingThreadCleanup()
+ pthread_join(keepAlivePingThread_t, NULL);
// Clean up
keepAlivePingThread_t = NULL;
@@ -202,6 +216,8 @@
*/
void _backgroundPingTask(void *ptr)
{
+ pthread_setname_np("SPMySQL _backgroundPingTask() worker thread");
+
SPMySQLConnectionPingDetails *pingDetails = (SPMySQLConnectionPingDetails *)ptr;
// Set up a cleanup routine
@@ -236,7 +252,7 @@ void _forceThreadExit(int signalNumber)
void _pingThreadCleanup(void *pingDetails)
{
SPMySQLConnectionPingDetails *pingDetailsStruct = pingDetails;
- *(pingDetailsStruct->keepAlivePingActivePointer) = NO;
+ *(pingDetailsStruct->keepAlivePingThreadActivePointer) = NO;
// Clean up MySQL variables and handlers
mysql_thread_end();
@@ -248,24 +264,28 @@ void _pingThreadCleanup(void *pingDetails)
/**
* If a keepalive thread is active, cancel it, and wait a short time for it
* to exit.
+ *
+ * @return YES, if the thread exited within 10 seconds after canceling it
*/
-- (void)_cancelKeepAlives
+- (BOOL)_cancelKeepAlives
{
// If no keepalive thread is active, return
- if (!keepAliveThread) {
- return;
+ if (keepAliveThread) {
+
+ // Mark the thread as cancelled
+ [keepAliveThread cancel];
+
+ // Wait inside a time limit of ten seconds for it to exit
+ uint64_t threadCancelStartTime_t = mach_absolute_time();
+ do {
+ usleep(100000);
+ if (_elapsedSecondsSinceAbsoluteTime(threadCancelStartTime_t) > 10) return NO;
+ } while (keepAliveThread);
+
}
-
- // Mark the thread as cancelled
- [keepAliveThread cancel];
-
- // Wait inside a time limit of ten seconds for it to exit
- uint64_t threadCancelStartTime_t = mach_absolute_time();
- do {
- usleep(100000);
- if (_elapsedSecondsSinceAbsoluteTime(threadCancelStartTime_t) > 10) break;
- } while (keepAliveThread);
+
+ return YES;
}
@end
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Querying & Preparation.m b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Querying & Preparation.m
index 48f4fc1e..d96ebe52 100644
--- a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Querying & Preparation.m
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Querying & Preparation.m
@@ -58,6 +58,9 @@
* Take a string and escapes any special character for safe use within a query; correctly
* escapes any characters within the string using the current connection encoding.
* Allows control over whether to also wrap the string in single quotes.
+ *
+ * WARNING: This method may return nil if the current thread is cancelled!
+ * You MUST check the isCancelled flag before using the result!
*/
- (NSString *)escapeString:(NSString *)theString includingQuotes:(BOOL)includeQuotes
{
@@ -72,11 +75,12 @@
}
return nil;
}
- if (![self _checkConnectionIfNecessary]) return nil;
// Ensure per-thread variables are set up
[self _validateThreadSetup];
+ if (![self _checkConnectionIfNecessary]) return nil;
+
// Perform a lossy conversion to bytes, using NSData to do the hard work. Preserves
// nul characters correctly.
NSData *cData = [theString dataUsingEncoding:stringEncoding allowLossyConversion:YES];
@@ -221,6 +225,9 @@
* the connection encoding.
* The result type desired can be specified, supporting either standard or streaming
* result sets.
+ *
+ * WARNING: This method may return nil if the current thread is cancelled!
+ * You MUST check the isCancelled flag before using the result!
*/
- (id)queryString:(NSString *)theQueryString usingEncoding:(NSStringEncoding)theEncoding withResultType:(SPMySQLResultType)theReturnType
{
@@ -288,7 +295,8 @@
// Lock the connection while it's actively in use
[self _lockConnection];
- while (queryAttemptsAllowed > 0) {
+ unsigned long long theAffectedRowCount;
+ do {
// While recording the overall execution time (including network lag!), run
// the raw query
@@ -296,6 +304,11 @@
queryStatus = mysql_real_query(mySQLConnection, queryBytes, queryBytesLength);
queryExecutionTime = _elapsedSecondsSinceAbsoluteTime(queryStartTime);
lastConnectionUsedTime = mach_absolute_time();
+
+ // "An integer greater than zero indicates the number of rows affected or retrieved.
+ // Zero indicates that no records were updated for an UPDATE statement, no rows matched the WHERE clause in the query or that no query has yet been executed.
+ // -1 indicates that the query returned an error or that, for a SELECT query, mysql_affected_rows() was called prior to calling mysql_store_result()."
+ theAffectedRowCount = mysql_affected_rows(mySQLConnection);
// If the query succeeded, no need to re-attempt.
if (!queryStatus) {
@@ -313,7 +326,7 @@
theSqlstate = [self _stringForCString:mysql_sqlstate(mySQLConnection)];
// Prevent retries if the query was cancelled or not a connection error
- if (lastQueryWasCancelled || ![SPMySQLConnection isErrorIDConnectionError:mysql_errno(mySQLConnection)]) {
+ if (lastQueryWasCancelled || ![SPMySQLConnection isErrorIDConnectionError:theErrorID]) {
break;
}
}
@@ -327,11 +340,10 @@
return nil;
}
[self _lockConnection];
+ NSAssert(mySQLConnection != NULL, @"mySQLConnection has disappeared while checking it!");
- queryAttemptsAllowed--;
- }
+ } while (--queryAttemptsAllowed > 0);
- unsigned long long theAffectedRowCount = mysql_affected_rows(mySQLConnection);
id theResult = nil;
// On success, if there is a query result, retrieve the result data type
@@ -660,6 +672,16 @@
}
/**
+ * Update lastErrorID, lastErrorMessage and lastSqlstate from connection
+ */
+- (void)_updateLastErrorInfos
+{
+ [self _updateLastErrorID:NSNotFound];
+ [self _updateLastErrorMessage:nil];
+ [self _updateLastSqlstate:nil];
+}
+
+/**
* Update the MySQL error message for this connection. If an error is supplied
* it will be stored and returned to anything asking the instance for the last
* error; if no error is supplied, the connection will be used to derive (or clear)
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Server Info.h b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Server Info.h
index 82607cdb..8ec6c9e0 100644
--- a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Server Info.h
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Server Info.h
@@ -45,4 +45,14 @@
- (SPMySQLResult *)listProcesses;
- (BOOL)killQueryOnThreadID:(unsigned long)theThreadID;
+/**
+ * mysql_shutdown() - If the user has the permission, will shutdown the (remote) server
+ * @return Whether the command was executed successfully
+ * Note: this can also be NO if the user denied a reconnect attempt.
+ *
+ * WARNING: This method may return NO if the current thread is cancelled!
+ * You MUST check the isCancelled flag before using the result!
+ */
+- (BOOL)serverShutdown;
+
@end
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Server Info.m b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Server Info.m
index dd684c78..db846929 100644
--- a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Server Info.m
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Server Info.m
@@ -46,54 +46,34 @@
return [NSString stringWithString:serverVariableVersion];
}
-#warning FIXME: There is probably a race condition here with -[self _disconnect]
- if(mySQLConnection) {
- return [self _stringForCString:mysql_get_server_info(mySQLConnection)];
- }
-
return nil;
}
/**
- * Return the server major version or NSNotFound on failure
+ * Return the server major version or 0 on failure
*/
- (NSUInteger)serverMajorVersion
{
- NSString *ver;
- if ((ver = [self serverVersionString]) != nil) {
- NSString *s = [[ver componentsSeparatedByString:@"."] objectAtIndex:0];
- return (NSUInteger)[s integerValue];
- }
-
- return NSNotFound;
+ // 5.5.33 => 50533 / 10'000 => 5.0533 => 5
+ return (serverVersionNumber / 10000);
}
/**
- * Return the server minor version or NSNotFound on failure
+ * Return the server minor version or 0 on failure
*/
- (NSUInteger)serverMinorVersion
{
- NSString *ver;
- if ((ver = [self serverVersionString]) != nil) {
- NSString *s = [[ver componentsSeparatedByString:@"."] objectAtIndex:1];
- return (NSUInteger)[s integerValue];
- }
-
- return NSNotFound;
+ // 5.5.33 => 50533 - (5*10'000) => 533 / 100 => 5.33 => 5
+ return ((serverVersionNumber - [self serverMajorVersion]*10000) / 100);
}
/**
- * Return the server release version or NSNotFound on failure
+ * Return the server release version or 0 on failure
*/
- (NSUInteger)serverReleaseVersion
{
- NSString *ver;
- if ((ver = [self serverVersionString]) != nil) {
- NSString *s = [[ver componentsSeparatedByString:@"."] objectAtIndex:2];
- return (NSUInteger)[[[s componentsSeparatedByString:@"-"] objectAtIndex:0] integerValue];
- }
-
- return NSNotFound;
+ // 5.5.33 => 50533 - (5*10'000 + 5*100) => 33
+ return (serverVersionNumber - ([self serverMajorVersion]*10000 + [self serverMinorVersion]*100));
}
#pragma mark -
@@ -105,23 +85,9 @@
*/
- (BOOL)serverVersionIsGreaterThanOrEqualTo:(NSUInteger)aMajorVersion minorVersion:(NSUInteger)aMinorVersion releaseVersion:(NSUInteger)aReleaseVersion
{
- NSString *ver;
- if (!(ver = [self serverVersionString])) return NO;
-
- NSArray *serverVersionParts = [ver componentsSeparatedByString:@"."];
-
- NSUInteger serverMajorVersion = (NSUInteger)[[serverVersionParts objectAtIndex:0] integerValue];
- if (serverMajorVersion < aMajorVersion) return NO;
- if (serverMajorVersion > aMajorVersion) return YES;
+ unsigned long myver = aMajorVersion * 10000 + aMinorVersion * 100 + aReleaseVersion;
- NSUInteger serverMinorVersion = (NSUInteger)[[serverVersionParts objectAtIndex:1] integerValue];
- if (serverMinorVersion < aMinorVersion) return NO;
- if (serverMinorVersion > aMinorVersion) return YES;
-
- NSString *serverReleasePart = [serverVersionParts objectAtIndex:2];
- NSUInteger serverReleaseVersion = (NSUInteger)[[[serverReleasePart componentsSeparatedByString:@"-"] objectAtIndex:0] integerValue];
- if (serverReleaseVersion < aReleaseVersion) return NO;
- return YES;
+ return (serverVersionNumber >= myver);
}
#pragma mark -
@@ -132,6 +98,9 @@
* the resulting process list defaults to the short form; run a manual SHOW FULL PROCESSLIST
* to retrieve tasks in non-truncated form.
* Returns nil on error.
+ *
+ * WARNING: This method may return nil if the current thread is cancelled!
+ * You MUST check the isCancelled flag before using the result!
*/
- (SPMySQLResult *)listProcesses
{
@@ -182,4 +151,21 @@
return ![self queryErrored];
}
+- (BOOL)serverShutdown
+{
+ if([self _checkConnectionIfNecessary]) {
+ [self _lockConnection];
+ // Ensure per-thread variables are set up
+ [self _validateThreadSetup];
+ //only SHUTDOWN_DEFAULT is supported right now
+ int res = mysql_shutdown(mySQLConnection, SHUTDOWN_DEFAULT);
+ //update or clear error
+ [self _updateLastErrorInfos];
+ [self _unlockConnection];
+
+ return (res == 0);
+ }
+ return NO;
+}
+
@end
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.h b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.h
index c65ec2fb..15b809f1 100644
--- a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.h
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.h
@@ -85,10 +85,8 @@
CGFloat keepAliveInterval;
uint64_t lastKeepAliveTime;
NSUInteger keepAlivePingFailures;
- NSThread *keepAliveThread;
- pthread_t keepAlivePingThread_t;
- BOOL keepAlivePingThreadActive;
- BOOL keepAliveLastPingSuccess;
+ volatile NSThread *keepAliveThread;
+ volatile BOOL keepAlivePingThreadActive;
BOOL keepAliveLastPingBlocked;
// Encoding details - and also a record of any previous encoding to allow
@@ -101,6 +99,7 @@
// Server details
NSString *serverVariableVersion;
+ unsigned long serverVersionNumber;
// Error state for the last query or connection state
NSUInteger queryErrorID;
@@ -129,6 +128,8 @@
BOOL retryQueriesOnConnectionFailure;
SPMySQLClientFlags clientFlags;
+
+ NSString *_debugLastConnectedEvent;
}
#pragma mark -
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m
index 40c95321..286296af 100644
--- a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m
@@ -145,9 +145,7 @@ const char *SPMySQLSSLPermissibleCiphers = "DHE-RSA-AES256-SHA:AES256-SHA:DHE-RS
keepAlivePingFailures = 0;
lastKeepAliveTime = 0;
keepAliveThread = nil;
- keepAlivePingThread_t = NULL;
keepAlivePingThreadActive = NO;
- keepAliveLastPingSuccess = NO;
keepAliveLastPingBlocked = NO;
// Set up default encoding variables
@@ -176,6 +174,7 @@ const char *SPMySQLSSLPermissibleCiphers = "DHE-RSA-AES256-SHA:AES256-SHA:DHE-RS
// Ensure the server detail records are initialised
serverVariableVersion = nil;
+ serverVersionNumber = 0;
// Start with a blank error state
queryErrorID = 0;
@@ -200,6 +199,8 @@ const char *SPMySQLSSLPermissibleCiphers = "DHE-RSA-AES256-SHA:AES256-SHA:DHE-RS
// while running them
retryQueriesOnConnectionFailure = YES;
+ _debugLastConnectedEvent = nil;
+
// Start the ping keepalive timer
keepAliveTimer = [[SPMySQLKeepAliveTimer alloc] initWithInterval:10 target:self selector:@selector(_keepAlive)];
@@ -254,6 +255,8 @@ const char *SPMySQLSSLPermissibleCiphers = "DHE-RSA-AES256-SHA:AES256-SHA:DHE-RS
if (querySqlstate) [querySqlstate release], querySqlstate = nil;
[delegateDecisionLock release];
+ [_debugLastConnectedEvent release];
+
[NSObject cancelPreviousPerformRequestsWithTarget:self];
[super dealloc];
@@ -279,6 +282,9 @@ const char *SPMySQLSSLPermissibleCiphers = "DHE-RSA-AES256-SHA:AES256-SHA:DHE-RS
* Error checks extensively - if this method fails, it will ask how to proceed and loop depending
* on the status, not returning control until either a connection has been established or
* the connection and document have been closed.
+ *
+ * WARNING: This method may exit early returning NO if the current thread is cancelled!
+ * You MUST check the isCancelled flag before using the result!
*/
- (BOOL)reconnect
{
@@ -327,10 +333,12 @@ const char *SPMySQLSSLPermissibleCiphers = "DHE-RSA-AES256-SHA:AES256-SHA:DHE-RS
* Checks whether the connection to the server is still active. This verifies
* the connection using a ping, and if the connection is found to be down attempts
* to quickly restore it, including the previous state.
+ *
+ * WARNING: This method may return NO if the current thread is cancelled!
+ * You MUST check the isCancelled flag before using the result!
*/
- (BOOL)checkConnection
{
-
// If the connection is not seen as active, don't proceed
if (state != SPMySQLConnected) return NO;
@@ -429,6 +437,14 @@ const char *SPMySQLSSLPermissibleCiphers = "DHE-RSA-AES256-SHA:AES256-SHA:DHE-RS
const char *__crashreporter_info__ = NULL;
asm(".desc ___crashreporter_info__, 0x10");
+static uint64_t _elapsedMicroSecondsSinceAbsoluteTime(uint64_t comparisonTime)
+{
+ uint64_t elapsedTime_t = mach_absolute_time() - comparisonTime;
+ Nanoseconds elapsedTime = AbsoluteToNanoseconds(*(AbsoluteTime *)&(elapsedTime_t));
+
+ return (UnsignedWideToUInt64(elapsedTime) / 1000ULL);
+}
+
@implementation SPMySQLConnection (PrivateAPI)
/**
@@ -439,8 +455,11 @@ asm(".desc ___crashreporter_info__, 0x10");
// If a connection is already active in some form, throw an exception
if (state != SPMySQLDisconnected && state != SPMySQLConnectionLostInBackground) {
- asprintf(&__crashreporter_info__, "Attempted to connect a connection that is not disconnected (SPMySQLConnectionState=%d).", state);
- __builtin_trap();
+ @synchronized (self) {
+ uint64_t diff = _elapsedMicroSecondsSinceAbsoluteTime(initialConnectTime);
+ asprintf(&__crashreporter_info__, "Attempted to connect a connection that is not disconnected (SPMySQLConnectionState=%d).\nIf state==2: Previous connection made %lluµs ago from: %s", state, diff, [_debugLastConnectedEvent cStringUsingEncoding:NSUTF8StringEncoding]);
+ __builtin_trap();
+ }
[NSException raise:NSInternalInconsistencyException format:@"Attempted to connect a connection that is not disconnected (SPMySQLConnectionState=%d).", state];
return NO;
}
@@ -466,17 +485,36 @@ asm(".desc ___crashreporter_info__, 0x10");
// If the connection was cancelled, clean up and don't continue
if (userTriggeredDisconnect) {
mysql_close(mySQLConnection);
- [self _unlockConnection];
mySQLConnection = NULL;
+ [self _unlockConnection];
return NO;
}
// Successfully connected - record connected state and reset tracking variables
state = SPMySQLConnected;
- initialConnectTime = mach_absolute_time();
+
+ @synchronized (self) {
+ initialConnectTime = mach_absolute_time();
+ [_debugLastConnectedEvent release];
+ _debugLastConnectedEvent = [[NSString alloc] initWithFormat:@"thread=%@ stack=%@",[NSThread currentThread],[NSThread callStackSymbols]];
+ }
+
mysqlConnectionThreadId = mySQLConnection->thread_id;
lastConnectionUsedTime = initialConnectTime;
+ // Copy the server version string to the instance variable
+ if (serverVariableVersion) [serverVariableVersion release], serverVariableVersion = nil;
+ // the mysql_get_server_info() function
+ // * returns the version name that is part of the initial connection handshake.
+ // * Unless the connection failed, it will always return a non-null buffer containing at least a '\0'.
+ // * It will never affect the error variables (since it only returns a struct member)
+ //
+ // At that point (handshake) there is no charset and it's highly unlikely this will ever contain something other than ASCII,
+ // but to be safe, we'll use the Latin1 encoding which won't bail on invalid chars.
+ serverVariableVersion = [[NSString alloc] initWithCString:mysql_get_server_info(mySQLConnection) encoding:NSISOLatin1StringEncoding];
+ // this one can actually change the error state, but only if the server version string is not set (ie. no connection)
+ serverVersionNumber = mysql_get_server_version(mySQLConnection);
+
// Update SSL state
connectedWithSSL = NO;
if (useSSL) connectedWithSSL = (mysql_get_ssl_cipher(mySQLConnection))?YES:NO;
@@ -491,9 +529,7 @@ asm(".desc ___crashreporter_info__, 0x10");
keepAlivePingFailures = 0;
// Clear the connection error record
- [self _updateLastErrorID:NSNotFound];
- [self _updateLastErrorMessage:nil];
- [self _updateLastSqlstate:nil];
+ [self _updateLastErrorInfos];
// Unlock the connection
[self _unlockConnection];
@@ -526,10 +562,7 @@ asm(".desc ___crashreporter_info__, 0x10");
// Calling mysql_init will have automatically installed per-thread variables if necessary,
// so track their installation for removal and to avoid recreating again.
- if (!pthread_getspecific(mySQLThreadInitFlagKey)) {
- pthread_setspecific(mySQLThreadInitFlagKey, &mySQLThreadFlag);
- [(NSNotificationCenter *)[NSNotificationCenter defaultCenter] addObserver:[self class] selector:@selector(_removeThreadVariables:) name:NSThreadWillExitNotification object:[NSThread currentThread]];
- }
+ [self _validateThreadSetup];
// Disable automatic reconnection, as it's handled in-framework to preserve
// options, encodings and connection state.
@@ -619,6 +652,9 @@ asm(".desc ___crashreporter_info__, 0x10");
* the connection and document have been closed.
* Runs its own autorelease pool as sometimes called in a thread following proxy changes
* (where the return code doesn't matter).
+ *
+ * WARNING: This method may exit early returning NO if the current thread is cancelled!
+ * You MUST check the isCancelled flag before using the result!
*/
- (BOOL)_reconnectAllowingRetries:(BOOL)canRetry
{
@@ -892,11 +928,15 @@ asm(".desc ___crashreporter_info__, 0x10");
uint64_t disconnectStartTime_t = mach_absolute_time();
while (![self _tryLockConnection]) {
usleep(100000);
- if (_elapsedSecondsSinceAbsoluteTime(disconnectStartTime_t) > 10) break;
+ if (_elapsedSecondsSinceAbsoluteTime(disconnectStartTime_t) > 10) {
+ NSLog(@"%s: Could not acquire connection lock within time limit (10s). Forcing unlock!",__PRETTY_FUNCTION__);
+ break;
+ }
}
[self _unlockConnection];
[self _cancelKeepAlives];
+ [self _lockConnection];
// Close the underlying MySQL connection if it still appears to be active, and not reading
// or writing. While this may result in a leak of the MySQL object, it prevents crashes
// due to attempts to close a blocked/stuck connection.
@@ -904,17 +944,16 @@ asm(".desc ___crashreporter_info__, 0x10");
mysql_close(mySQLConnection);
}
mySQLConnection = NULL;
+ if (serverVariableVersion) [serverVariableVersion release], serverVariableVersion = nil;
+ serverVersionNumber = 0;
+ if (database) [database release], database = nil;
+ state = SPMySQLDisconnected;
+ [self _unlockConnection];
// If using a connection proxy, disconnect that too
if (proxy) {
[proxy performSelectorOnMainThread:@selector(disconnect) withObject:nil waitUntilDone:YES];
}
-
- // Clear host-specific information
- if (serverVariableVersion) [serverVariableVersion release], serverVariableVersion = nil;
- if (database) [database release], database = nil;
-
- state = SPMySQLDisconnected;
}
/**
@@ -939,19 +978,32 @@ asm(".desc ___crashreporter_info__, 0x10");
[variables setObject:[variableRow objectAtIndex:1] forKey:[variableRow objectAtIndex:0]];
}
- // Copy the server version string to the instance variable
- if (serverVariableVersion) [serverVariableVersion release], serverVariableVersion = nil;
- serverVariableVersion = [[variables objectForKey:@"version"] retain];
-
// Get the connection encoding. Although a specific encoding may have been requested on
// connection, it may be overridden by init_connect commands or connection state changes.
// Default to latin1 for older server versions.
NSString *retrievedEncoding = @"latin1";
+ // character_set_results is the charset the strings received from the server will be in
if ([variables objectForKey:@"character_set_results"]) {
retrievedEncoding = [variables objectForKey:@"character_set_results"];
- } else if ([variables objectForKey:@"character_set"]) {
+ }
+ // not used in 4.1+ (?)
+ else if ([variables objectForKey:@"character_set"]) {
retrievedEncoding = [variables objectForKey:@"character_set"];
}
+ // character_set_client is the charset the server expects strings transmitted by us to be in
+ else if ([variables objectForKey:@"character_set_client"]) {
+ retrievedEncoding = [variables objectForKey:@"character_set_client"]; // fallback for sphinxql
+ }
+ // character_set_connection is used internally by the server for comparisons.
+ // String literals (without a cast) will always be converted from character_set_client to character_set_connection first.
+ // As an example:
+ // * Use a client with "SET NAMES utf8"
+ // * Do a "set @@session.character_set_connection = 'latin1';"
+ // * Finally try a "SELECT '犬';" (also try "select _utf8'犬';" for completeness)
+ // * The result will just show a "?"
+ // So even though we told the server that the client uses utf8 and the results
+ // should be encoded in utf8, too, the character got lost.
+ // This happened because the server did a roundtrip of utf8 -> latin1 -> utf8.
// Update instance variables
if (encoding) [encoding release];
@@ -995,6 +1047,9 @@ asm(".desc ___crashreporter_info__, 0x10");
* each of which requires a round trip to the server - but handles most
* network issues.
* Returns whether the connection is considered still valid.
+ *
+ * WARNING: This method may return NO if the current thread is cancelled!
+ * You MUST check the isCancelled flag before using the result!
*/
- (BOOL)_checkConnectionIfNecessary
{
@@ -1018,21 +1073,22 @@ asm(".desc ___crashreporter_info__, 0x10");
* Ensure that the thread this method is called on has been registered for
* use with MySQL. MySQL requires thread-specific variables for safe
* execution.
+ *
+ * Calling this multiple times per thread is OK.
*/
- (void)_validateThreadSetup
{
-
// Check to see whether the handler has already been installed
if (pthread_getspecific(mySQLThreadInitFlagKey)) return;
// If not, install it
- mysql_thread_init();
+ mysql_thread_init(); // multiple calls per thread OK.
// Mark the thread to avoid multiple installs
pthread_setspecific(mySQLThreadInitFlagKey, &mySQLThreadFlag);
// Set up the notification handler to deregister it
- [(NSNotificationCenter *)[NSNotificationCenter defaultCenter] addObserver:[self class] selector:@selector(_removeThreadVariables:) name:NSThreadWillExitNotification object:[NSThread currentThread]];
+ [[NSNotificationCenter defaultCenter] addObserver:[self class] selector:@selector(_removeThreadVariables:) name:NSThreadWillExitNotification object:[NSThread currentThread]];
}
/**
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLFastStreamingResult.m b/Frameworks/SPMySQLFramework/Source/SPMySQLFastStreamingResult.m
index 930180da..53ab116f 100644
--- a/Frameworks/SPMySQLFramework/Source/SPMySQLFastStreamingResult.m
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLFastStreamingResult.m
@@ -392,9 +392,7 @@ typedef struct st_spmysqlstreamingrowdata {
}
// Update the connection's error statuses to reflect any errors during the content download
- [parentConnection _updateLastErrorID:NSNotFound];
- [parentConnection _updateLastErrorMessage:nil];
- [parentConnection _updateLastSqlstate:nil];
+ [parentConnection _updateLastErrorInfos];
// Unlock the parent connection now all data has been retrieved
[parentConnection _unlockConnection];
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLResult Categories/Data Conversion.h b/Frameworks/SPMySQLFramework/Source/SPMySQLResult Categories/Data Conversion.h
index 817d2cb7..7d865226 100644
--- a/Frameworks/SPMySQLFramework/Source/SPMySQLResult Categories/Data Conversion.h
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLResult Categories/Data Conversion.h
@@ -30,12 +30,7 @@
@interface SPMySQLResult (Data_Conversion_Private_API)
++ (void)_initializeDataConversion;
- (id)_getObjectFromBytes:(char *)bytes ofLength:(NSUInteger)length fieldDefinitionIndex:(NSUInteger)fieldIndex previewLength:(NSUInteger)previewLength;
-static inline SPMySQLResultFieldProcessor _processorForField(MYSQL_FIELD aField);
-
-static inline NSString * _stringWithBytes(const void *dataBytes, NSUInteger dataLength, NSStringEncoding aStringEncoding, NSUInteger previewLength);
-static inline NSString * _bitStringWithBytes(const char *bytes, NSUInteger length, NSUInteger padLength);
-static inline NSString * _convertStringData(const void *dataBytes, NSUInteger dataLength, NSStringEncoding aStringEncoding, NSUInteger previewLength);
-
@end
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLResult Categories/Data Conversion.m b/Frameworks/SPMySQLFramework/Source/SPMySQLResult Categories/Data Conversion.m
index 639ff0b9..3b29fb5e 100644
--- a/Frameworks/SPMySQLFramework/Source/SPMySQLResult Categories/Data Conversion.m
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLResult Categories/Data Conversion.m
@@ -31,6 +31,16 @@
#import "Data Conversion.h"
+#ifdef SPMYSQL_FOR_UNIT_TESTING
+#define PRIVATE /* public */
+#else
+#define PRIVATE static inline
+#endif
+
+PRIVATE SPMySQLResultFieldProcessor _processorForField(MYSQL_FIELD aField);
+PRIVATE NSString * _bitStringWithBytes(const char *bytes, NSUInteger length, NSUInteger padLength);
+PRIVATE NSString * _convertStringData(const void *dataBytes, NSUInteger dataLength, NSStringEncoding aStringEncoding, NSUInteger previewLength);
+
static SPMySQLResultFieldProcessor fieldProcessingMap[256];
static id NSNullPointer;
static NSStringEncoding NSFromCFStringEncodingBig5;
@@ -68,6 +78,7 @@ static NSStringEncoding NSFromCFStringEncodingGBK_95;
fieldProcessingMap[MYSQL_TYPE_NEWDATE] = SPMySQLResultFieldAsString;
fieldProcessingMap[MYSQL_TYPE_VARCHAR] = SPMySQLResultFieldAsString;
fieldProcessingMap[MYSQL_TYPE_BIT] = SPMySQLResultFieldAsBit;
+ fieldProcessingMap[MYSQL_TYPE_JSON] = SPMySQLResultFieldAsString;
fieldProcessingMap[MYSQL_TYPE_NEWDECIMAL] = SPMySQLResultFieldAsString;
fieldProcessingMap[MYSQL_TYPE_ENUM] = SPMySQLResultFieldAsString;
fieldProcessingMap[MYSQL_TYPE_SET] = SPMySQLResultFieldAsString;
@@ -161,10 +172,12 @@ static NSStringEncoding NSFromCFStringEncodingGBK_95;
return nil;
}
+@end
+
/**
* Returns the field processor to use for a specified field.
*/
-static inline SPMySQLResultFieldProcessor _processorForField(MYSQL_FIELD aField)
+PRIVATE SPMySQLResultFieldProcessor _processorForField(MYSQL_FIELD aField)
{
// Determine the default field processor to use
SPMySQLResultFieldProcessor dataProcessor = fieldProcessingMap[aField.type];
@@ -200,7 +213,7 @@ static inline SPMySQLResultFieldProcessor _processorForField(MYSQL_FIELD aField)
* field length.
* MySQL stores bit data as string data stored in an 8-bit wide character set.
*/
-static inline NSString * _bitStringWithBytes(const char *bytes, NSUInteger length, NSUInteger padLength)
+PRIVATE NSString * _bitStringWithBytes(const char *bytes, NSUInteger length, NSUInteger padLength)
{
NSUInteger i = 0;
NSUInteger bitLength = length << 3;
@@ -209,27 +222,26 @@ static inline NSString * _bitStringWithBytes(const char *bytes, NSUInteger lengt
return nil;
}
- // Ensure padLength is never lower than the length
- if (padLength < bitLength) {
- padLength = bitLength;
- }
-
+ // use whatever is smaller. padLength comes from BIT(x), bitLength from the actual bytes transmitted.
+ // if bitLength < padLength it means the value is smaller than what the field can accomodate.
+ // if bitLength > padLength it means BIT(x) is not a full n bytes long and was extended by mysqls storage.
+ // In that case the additional bits should still be 0 as mysql does not allow to set bits over the size of x.
+ bitLength = MIN(bitLength,padLength);
// Generate a nul-terminated C string representation of the binary data
char *cStringBuffer = malloc(padLength + 1);
- cStringBuffer[padLength] = '\0';
+ memset(cStringBuffer, '0', padLength);
while (i < bitLength)
{
+ // start with the least significant bit (the rightmost bit in the last byte) and move left
+ unsigned char bitInByteMask = i % 8; // 0-7, the cycle is 0,1,...,7,0,...
+ unsigned long bytesOffset = (length - 1) - (i >> 3); // i>>3 == floor(i/8)
++i;
-
- cStringBuffer[padLength - i] = ((bytes[length - 1 - (i >> 3)] >> (i & 0x7)) & 1 ) ? '1' : '0';
+ cStringBuffer[padLength - i] = ((bytes[bytesOffset] & (1 << bitInByteMask)) != 0) ? '1' : '0';
}
-
- while (i++ < padLength)
- {
- cStringBuffer[padLength - i] = '0';
- }
-
+
+ cStringBuffer[padLength] = '\0';
+
// Convert to a string
NSString *returnString = [NSString stringWithUTF8String:cStringBuffer];
@@ -243,7 +255,7 @@ static inline NSString * _bitStringWithBytes(const char *bytes, NSUInteger lengt
* Converts stored string data - which may contain nul bytes - to a native
* Objective-C string, using the current class encoding.
*/
-static inline NSString * _convertStringData(const void *dataBytes, NSUInteger dataLength, NSStringEncoding aStringEncoding, NSUInteger previewLength)
+PRIVATE NSString * _convertStringData(const void *dataBytes, NSUInteger dataLength, NSStringEncoding aStringEncoding, NSUInteger previewLength)
{
// Fast case - if not using a preview length, or if the data length is shorter, return the requested data.
@@ -414,5 +426,4 @@ static inline NSString * _convertStringData(const void *dataBytes, NSUInteger da
return previewString;
}
-
-@end
+#undef PRIVATE
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLResult Categories/Field Definitions.m b/Frameworks/SPMySQLFramework/Source/SPMySQLResult Categories/Field Definitions.m
index c61b9140..ec52e0e3 100644
--- a/Frameworks/SPMySQLFramework/Source/SPMySQLResult Categories/Field Definitions.m
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLResult Categories/Field Definitions.m
@@ -29,6 +29,7 @@
// More info at <https://github.com/sequelpro/sequelpro>
#import "Field Definitions.h"
+#import "SPMySQL Private APIs.h"
@interface SPMySQLResult (Field_Definitions_Private_API)
@@ -40,14 +41,6 @@
@end
-// Import a private declaration from the SPMySQLResult file for use
-@interface SPMySQLResult (Private_API)
-
-- (NSString *)_stringWithBytes:(const void *)bytes length:(NSUInteger)length;
-- (NSString *)_lossyStringWithBytes:(const void *)bytes length:(NSUInteger)length wasLossy:(BOOL *)outLossy;
-
-@end
-
#define MAGIC_BINARY_CHARSET_NR 63
const SPMySQLResultCharset SPMySQLCharsetMap[] =
@@ -379,7 +372,7 @@ const SPMySQLResultCharset SPMySQLCharsetMap[] =
switch (type) {
- case FIELD_TYPE_BIT:
+ case MYSQL_TYPE_BIT:
return @"BIT";
case MYSQL_TYPE_DECIMAL:
@@ -482,6 +475,9 @@ const SPMySQLResultCharset SPMySQLCharsetMap[] =
case MYSQL_TYPE_GEOMETRY:
return @"GEOMETRY";
+
+ case MYSQL_TYPE_JSON:
+ return @"JSON";
default:
return @"UNKNOWN";
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLResult.m b/Frameworks/SPMySQLFramework/Source/SPMySQLResult.m
index 5f54960c..2e1cb2ba 100644
--- a/Frameworks/SPMySQLFramework/Source/SPMySQLResult.m
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLResult.m
@@ -318,7 +318,7 @@ static id NSNullPointer;
{
return [[[NSString alloc] initWithBytes:bytes length:length encoding:stringEncoding] autorelease];
}
-
+#warning duplicate code with Data Conversion.m stringForDataBytes:length:encoding: (↑, ↓)
- (NSString *)_lossyStringWithBytes:(const void *)bytes length:(NSUInteger)length wasLossy:(BOOL *)outLossy
{
if(!bytes || !length) return @""; //to match -[NSString initWithBytes:length:encoding:]
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLStreamingResultStore.h b/Frameworks/SPMySQLFramework/Source/SPMySQLStreamingResultStore.h
index d66dfd81..5fa6f406 100644
--- a/Frameworks/SPMySQLFramework/Source/SPMySQLStreamingResultStore.h
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLStreamingResultStore.h
@@ -79,7 +79,7 @@ static inline unsigned long long SPMySQLResultStoreGetRowCount(SPMySQLStreamingR
{
typedef unsigned long long (*SPMSRSRowCountMethodPtr)(SPMySQLStreamingResultStore*, SEL);
static SPMSRSRowCountMethodPtr SPMSRSRowCount;
- if (!SPMSRSRowCount) SPMSRSRowCount = (SPMSRSRowCountMethodPtr)[self methodForSelector:@selector(numberOfRows)];
+ if (!SPMSRSRowCount) SPMSRSRowCount = (SPMSRSRowCountMethodPtr)[SPMySQLStreamingResultStore instanceMethodForSelector:@selector(numberOfRows)];
return SPMSRSRowCount(self, @selector(numberOfRows));
}
@@ -87,7 +87,7 @@ static inline id SPMySQLResultStoreGetRow(SPMySQLStreamingResultStore* self, NSU
{
typedef id (*SPMSRSRowFetchMethodPtr)(SPMySQLStreamingResultStore*, SEL, NSUInteger);
static SPMSRSRowFetchMethodPtr SPMSRSRowFetch;
- if (!SPMSRSRowFetch) SPMSRSRowFetch = (SPMSRSRowFetchMethodPtr)[self methodForSelector:@selector(rowContentsAtIndex:)];
+ if (!SPMSRSRowFetch) SPMSRSRowFetch = (SPMSRSRowFetchMethodPtr)[SPMySQLStreamingResultStore instanceMethodForSelector:@selector(rowContentsAtIndex:)];
return SPMSRSRowFetch(self, @selector(rowContentsAtIndex:), rowIndex);
}
@@ -95,7 +95,7 @@ static inline id SPMySQLResultStoreObjectAtRowAndColumn(SPMySQLStreamingResultSt
{
typedef id (*SPMSRSObjectFetchMethodPtr)(SPMySQLStreamingResultStore*, SEL, NSUInteger, NSUInteger);
static SPMSRSObjectFetchMethodPtr SPMSRSObjectFetch;
- if (!SPMSRSObjectFetch) SPMSRSObjectFetch = (SPMSRSObjectFetchMethodPtr)[self methodForSelector:@selector(cellDataAtRow:column:)];
+ if (!SPMSRSObjectFetch) SPMSRSObjectFetch = (SPMSRSObjectFetchMethodPtr)[SPMySQLStreamingResultStore instanceMethodForSelector:@selector(cellDataAtRow:column:)];
return SPMSRSObjectFetch(self, @selector(cellDataAtRow:column:), rowIndex, colIndex);
}
@@ -103,6 +103,6 @@ static inline id SPMySQLResultStorePreviewAtRowAndColumn(SPMySQLStreamingResultS
{
typedef id (*SPMSRSObjectPreviewMethodPtr)(SPMySQLStreamingResultStore*, SEL, NSUInteger, NSUInteger, NSUInteger);
static SPMSRSObjectPreviewMethodPtr SPMSRSObjectPreview;
- if (!SPMSRSObjectPreview) SPMSRSObjectPreview = (SPMSRSObjectPreviewMethodPtr)[self methodForSelector:@selector(cellPreviewAtRow:column:previewLength:)];
+ if (!SPMSRSObjectPreview) SPMSRSObjectPreview = (SPMSRSObjectPreviewMethodPtr)[SPMySQLStreamingResultStore instanceMethodForSelector:@selector(cellPreviewAtRow:column:previewLength:)];
return SPMSRSObjectPreview(self, @selector(cellPreviewAtRow:column:previewLength:), rowIndex, colIndex, previewLength);
}
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLStreamingResultStore.m b/Frameworks/SPMySQLFramework/Source/SPMySQLStreamingResultStore.m
index 86a6b2b5..29f83e0e 100644
--- a/Frameworks/SPMySQLFramework/Source/SPMySQLStreamingResultStore.m
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLStreamingResultStore.m
@@ -809,9 +809,7 @@ static inline void SPMySQLStreamingResultStoreFreeRowData(SPMySQLStreamingResult
}
// Update the connection's error statuses to reflect any errors during the content download
- [parentConnection _updateLastErrorID:NSNotFound];
- [parentConnection _updateLastErrorMessage:nil];
- [parentConnection _updateLastSqlstate:nil];
+ [parentConnection _updateLastErrorInfos];
// Unlock the parent connection now all data has been retrieved
[parentConnection _unlockConnection];