From 01284d6b966511902396f7837a27b6ec34425ff6 Mon Sep 17 00:00:00 2001 From: Oldes Date: Wed, 27 May 2020 18:38:04 +0200 Subject: [PATCH] FEAT: ported Nenad's MySQL driver to be compatible with this Rebol3 version as a module/scheme It's just a quick rewrite, which replaces original `debug` function in the protocol with system logging and some of required modifications. There is also minnor change in error reporting. It would deserve better rewrite, but I don't have much need for this, so it's left for future or someone else. It was tested only with this so far: ``` >> mysql: connect-sql mysql://root:rur@localhost/ [MySQL] Connected: mysql://root@localhost:3306/ >> send-sql mysql "show databases" == [["information_schema"] ["mysql"] ["performance_schema"] ["sys"] ["test"]] >> send-sql mysql "create database test" ** mysql error: [ 1007 ] "Can't create database 'test'; database exists" >> send-sql mysql "drop database test" == [] >> send-sql/flat mysql "show databases" == ["information_schema" "mysql" "performance_schema" "sys"] >> close mysql [MySQL] Closed: mysql://root@localhost:3306/ >> ``` --- src/include/sys-value.h | 1 + src/mezz/prot-mysql.r | 1061 +++++++-------------------------------- 2 files changed, 172 insertions(+), 890 deletions(-) diff --git a/src/include/sys-value.h b/src/include/sys-value.h index 35f35c1556..4fc1687249 100644 --- a/src/include/sys-value.h +++ b/src/include/sys-value.h @@ -997,6 +997,7 @@ typedef struct Reb_Path_Value { REBVAL *select; // modified REBVAL *path; // modified REBVAL *store; // modified (holds constructed values) + REBSER *setfrm; // modified REBVAL *setval; // static REBVAL *orig; // static } REBPVS; diff --git a/src/mezz/prot-mysql.r b/src/mezz/prot-mysql.r index 9fff8613e3..d72a78d98a 100644 --- a/src/mezz/prot-mysql.r +++ b/src/mezz/prot-mysql.r @@ -1,767 +1,49 @@ REBOL [ Title: "MySQL Protocol" - Authors: ["Nenad Rakocevic / SOFTINNOV" "Shixin Zeng "] - Email: mysql@softinnov.com - Web: http://softinnov.org/rebol/mysql.shtml - Date: - File: %mysql-protocol.r - Version: 2.0.0 Purpose: "MySQL Driver for REBOL" - GIT-COMMIT: "" -] -mysql-errors: [ -;imported from mysqld_error.h in libmysqtcp-port - ER_ERROR_FIRST 1000 - ER_HASHCHK 1000 - ER_NISAMCHK 1001 - ER_NO 1002 - ER_YES 1003 - ER_CANT_CREATE_FILE 1004 - ER_CANT_CREATE_TABLE 1005 - ER_CANT_CREATE_DB 1006 - ER_DB_CREATE_EXISTS 1007 - ER_DB_DROP_EXISTS 1008 - ER_DB_DROP_DELETE 1009 - ER_DB_DROP_RMDIR 1010 - ER_CANT_DELETE_FILE 1011 - ER_CANT_FIND_SYSTEM_REC 1012 - ER_CANT_GET_STAT 1013 - ER_CANT_GET_WD 1014 - ER_CANT_LOCK 1015 - ER_CANT_OPEN_FILE 1016 - ER_FILE_NOT_FOUND 1017 - ER_CANT_READ_DIR 1018 - ER_CANT_SET_WD 1019 - ER_CHECKREAD 1020 - ER_DISK_FULL 1021 - ER_DUP_KEY 1022 - ER_ERROR_ON_CLOSE 1023 - ER_ERROR_ON_READ 1024 - ER_ERROR_ON_RENAME 1025 - ER_ERROR_ON_WRITE 1026 - ER_FILE_USED 1027 - ER_FILSORT_ABORT 1028 - ER_FORM_NOT_FOUND 1029 - ER_GET_ERRNO 1030 - ER_ILLEGAL_HA 1031 - ER_KEY_NOT_FOUND 1032 - ER_NOT_FORM_FILE 1033 - ER_NOT_KEYFILE 1034 - ER_OLD_KEYFILE 1035 - ER_OPEN_AS_READONLY 1036 - ER_OUTOFMEMORY 1037 - ER_OUT_OF_SORTMEMORY 1038 - ER_UNEXPECTED_EOF 1039 - ER_CON_COUNT_ERROR 1040 - ER_OUT_OF_RESOURCES 1041 - ER_BAD_HOST_ERROR 1042 - ER_HANDSHAKE_ERROR 1043 - ER_DBACCESS_DENIED_ERROR 1044 - ER_ACCESS_DENIED_ERROR 1045 - ER_NO_DB_ERROR 1046 - ER_UNKNOWN_COM_ERROR 1047 - ER_BAD_NULL_ERROR 1048 - ER_BAD_DB_ERROR 1049 - ER_TABLE_EXISTS_ERROR 1050 - ER_BAD_TABLE_ERROR 1051 - ER_NON_UNIQ_ERROR 1052 - ER_SERVER_SHUTDOWN 1053 - ER_BAD_FIELD_ERROR 1054 - ER_WRONG_FIELD_WITH_GROUP 1055 - ER_WRONG_GROUP_FIELD 1056 - ER_WRONG_SUM_SELECT 1057 - ER_WRONG_VALUE_COUNT 1058 - ER_TOO_LONG_IDENT 1059 - ER_DUP_FIELDNAME 1060 - ER_DUP_KEYNAME 1061 - ER_DUP_ENTRY 1062 - ER_WRONG_FIELD_SPEC 1063 - ER_PARSE_ERROR 1064 - ER_EMPTY_QUERY 1065 - ER_NONUNIQ_TABLE 1066 - ER_INVALID_DEFAULT 1067 - ER_MULTIPLE_PRI_KEY 1068 - ER_TOO_MANY_KEYS 1069 - ER_TOO_MANY_KEY_PARTS 1070 - ER_TOO_LONG_KEY 1071 - ER_KEY_COLUMN_DOES_NOT_EXITS 1072 - ER_BLOB_USED_AS_KEY 1073 - ER_TOO_BIG_FIELDLENGTH 1074 - ER_WRONG_AUTO_KEY 1075 - ER_READY 1076 - ER_NORMAL_SHUTDOWN 1077 - ER_GOT_SIGNAL 1078 - ER_SHUTDOWN_COMPLETE 1079 - ER_FORCING_CLOSE 1080 - ER_IPSOCK_ERROR 1081 - ER_NO_SUCH_INDEX 1082 - ER_WRONG_FIELD_TERMINATORS 1083 - ER_BLOBS_AND_NO_TERMINATED 1084 - ER_TEXTFILE_NOT_READABLE 1085 - ER_FILE_EXISTS_ERROR 1086 - ER_LOAD_INFO 1087 - ER_ALTER_INFO 1088 - ER_WRONG_SUB_KEY 1089 - ER_CANT_REMOVE_ALL_FIELDS 1090 - ER_CANT_DROP_FIELD_OR_KEY 1091 - ER_INSERT_INFO 1092 - ER_UPDATE_TABLE_USED 1093 - ER_NO_SUCH_THREAD 1094 - ER_KILL_DENIED_ERROR 1095 - ER_NO_TABLES_USED 1096 - ER_TOO_BIG_SET 1097 - ER_NO_UNIQUE_LOGFILE 1098 - ER_TABLE_NOT_LOCKED_FOR_WRITE 1099 - ER_TABLE_NOT_LOCKED 1100 - ER_BLOB_CANT_HAVE_DEFAULT 1101 - ER_WRONG_DB_NAME 1102 - ER_WRONG_TABLE_NAME 1103 - ER_TOO_BIG_SELECT 1104 - ER_UNKNOWN_ERROR 1105 - ER_UNKNOWN_PROCEDURE 1106 - ER_WRONG_PARAMCOUNT_TO_PROCEDURE 1107 - ER_WRONG_PARAMETERS_TO_PROCEDURE 1108 - ER_UNKNOWN_TABLE 1109 - ER_FIELD_SPECIFIED_TWICE 1110 - ER_INVALID_GROUP_FUNC_USE 1111 - ER_UNSUPPORTED_EXTENSION 1112 - ER_TABLE_MUST_HAVE_COLUMNS 1113 - ER_RECORD_FILE_FULL 1114 - ER_UNKNOWN_CHARACTER_SET 1115 - ER_TOO_MANY_TABLES 1116 - ER_TOO_MANY_FIELDS 1117 - ER_TOO_BIG_ROWSIZE 1118 - ER_STACK_OVERRUN 1119 - ER_WRONG_OUTER_JOIN 1120 - ER_NULL_COLUMN_IN_INDEX 1121 - ER_CANT_FIND_UDF 1122 - ER_CANT_INITIALIZE_UDF 1123 - ER_UDF_NO_PATHS 1124 - ER_UDF_EXISTS 1125 - ER_CANT_OPEN_LIBRARY 1126 - ER_CANT_FIND_DL_ENTRY 1127 - ER_FUNCTION_NOT_DEFINED 1128 - ER_HOST_IS_BLOCKED 1129 - ER_HOST_NOT_PRIVILEGED 1130 - ER_PASSWORD_ANONYMOUS_USER 1131 - ER_PASSWORD_NOT_ALLOWED 1132 - ER_PASSWORD_NO_MATCH 1133 - ER_UPDATE_INFO 1134 - ER_CANT_CREATE_THREAD 1135 - ER_WRONG_VALUE_COUNT_ON_ROW 1136 - ER_CANT_REOPEN_TABLE 1137 - ER_INVALID_USE_OF_NULL 1138 - ER_REGEXP_ERROR 1139 - ER_MIX_OF_GROUP_FUNC_AND_FIELDS 1140 - ER_NONEXISTING_GRANT 1141 - ER_TABLEACCESS_DENIED_ERROR 1142 - ER_COLUMNACCESS_DENIED_ERROR 1143 - ER_ILLEGAL_GRANT_FOR_TABLE 1144 - ER_GRANT_WRONG_HOST_OR_USER 1145 - ER_NO_SUCH_TABLE 1146 - ER_NONEXISTING_TABLE_GRANT 1147 - ER_NOT_ALLOWED_COMMAND 1148 - ER_SYNTAX_ERROR 1149 - ER_DELAYED_CANT_CHANGE_LOCK 1150 - ER_TOO_MANY_DELAYED_THREADS 1151 - ER_ABORTING_CONNECTION 1152 - ER_NET_PACKET_TOO_LARGE 1153 - ER_NET_READ_ERROR_FROM_PIPE 1154 - ER_NET_FCNTL_ERROR 1155 - ER_NET_PACKETS_OUT_OF_ORDER 1156 - ER_NET_UNCOMPRESS_ERROR 1157 - ER_NET_READ_ERROR 1158 - ER_NET_READ_INTERRUPTED 1159 - ER_NET_ERROR_ON_WRITE 1160 - ER_NET_WRITE_INTERRUPTED 1161 - ER_TOO_LONG_STRING 1162 - ER_TABLE_CANT_HANDLE_BLOB 1163 - ER_TABLE_CANT_HANDLE_AUTO_INCREMENT 1164 - ER_DELAYED_INSERT_TABLE_LOCKED 1165 - ER_WRONG_COLUMN_NAME 1166 - ER_WRONG_KEY_COLUMN 1167 - ER_WRONG_MRG_TABLE 1168 - ER_DUP_UNIQUE 1169 - ER_BLOB_KEY_WITHOUT_LENGTH 1170 - ER_PRIMARY_CANT_HAVE_NULL 1171 - ER_TOO_MANY_ROWS 1172 - ER_REQUIRES_PRIMARY_KEY 1173 - ER_NO_RAID_COMPILED 1174 - ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE 1175 - ER_KEY_DOES_NOT_EXITS 1176 - ER_CHECK_NO_SUCH_TABLE 1177 - ER_CHECK_NOT_IMPLEMENTED 1178 - ER_CANT_DO_THIS_DURING_AN_TRANSACTION 1179 - ER_ERROR_DURING_COMMIT 1180 - ER_ERROR_DURING_ROLLBACK 1181 - ER_ERROR_DURING_FLUSH_LOGS 1182 - ER_ERROR_DURING_CHECKPOINT 1183 - ER_NEW_ABORTING_CONNECTION 1184 - ER_DUMP_NOT_IMPLEMENTED 1185 - ER_FLUSH_MASTER_BINLOG_CLOSED 1186 - ER_INDEX_REBUILD 1187 - ER_MASTER 1188 - ER_MASTER_NET_READ 1189 - ER_MASTER_NET_WRITE 1190 - ER_FT_MATCHING_KEY_NOT_FOUND 1191 - ER_LOCK_OR_ACTIVE_TRANSACTION 1192 - ER_UNKNOWN_SYSTEM_VARIABLE 1193 - ER_CRASHED_ON_USAGE 1194 - ER_CRASHED_ON_REPAIR 1195 - ER_WARNING_NOT_COMPLETE_ROLLBACK 1196 - ER_TRANS_CACHE_FULL 1197 - ER_SLAVE_MUST_STOP 1198 - ER_SLAVE_NOT_RUNNING 1199 - ER_BAD_SLAVE 1200 - ER_MASTER_INFO 1201 - ER_SLAVE_THREAD 1202 - ER_TOO_MANY_USER_CONNECTIONS 1203 - ER_SET_CONSTANTS_ONLY 1204 - ER_LOCK_WAIT_TIMEOUT 1205 - ER_LOCK_TABLE_FULL 1206 - ER_READ_ONLY_TRANSACTION 1207 - ER_DROP_DB_WITH_READ_LOCK 1208 - ER_CREATE_DB_WITH_READ_LOCK 1209 - ER_WRONG_ARGUMENTS 1210 - ER_NO_PERMISSION_TO_CREATE_USER 1211 - ER_UNION_TABLES_IN_DIFFERENT_DIR 1212 - ER_LOCK_DEADLOCK 1213 - ER_TABLE_CANT_HANDLE_FT 1214 - ER_CANNOT_ADD_FOREIGN 1215 - ER_NO_REFERENCED_ROW 1216 - ER_ROW_IS_REFERENCED 1217 - ER_CONNECT_TO_MASTER 1218 - ER_QUERY_ON_MASTER 1219 - ER_ERROR_WHEN_EXECUTING_COMMAND 1220 - ER_WRONG_USAGE 1221 - ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT 1222 - ER_CANT_UPDATE_WITH_READLOCK 1223 - ER_MIXING_NOT_ALLOWED 1224 - ER_DUP_ARGUMENT 1225 - ER_USER_LIMIT_REACHED 1226 - ER_SPECIFIC_ACCESS_DENIED_ERROR 1227 - ER_LOCAL_VARIABLE 1228 - ER_GLOBAL_VARIABLE 1229 - ER_NO_DEFAULT 1230 - ER_WRONG_VALUE_FOR_VAR 1231 - ER_WRONG_TYPE_FOR_VAR 1232 - ER_VAR_CANT_BE_READ 1233 - ER_CANT_USE_OPTION_HERE 1234 - ER_NOT_SUPPORTED_YET 1235 - ER_MASTER_FATAL_ERROR_READING_BINLOG 1236 - ER_SLAVE_IGNORED_TABLE 1237 - ER_INCORRECT_GLOBAL_LOCAL_VAR 1238 - ER_WRONG_FK_DEF 1239 - ER_KEY_REF_DO_NOT_MATCH_TABLE_REF 1240 - ER_OPERAND_COLUMNS 1241 - ER_SUBQUERY_NO_1_ROW 1242 - ER_UNKNOWN_STMT_HANDLER 1243 - ER_CORRUPT_HELP_DB 1244 - ER_CYCLIC_REFERENCE 1245 - ER_AUTO_CONVERT 1246 - ER_ILLEGAL_REFERENCE 1247 - ER_DERIVED_MUST_HAVE_ALIAS 1248 - ER_SELECT_REDUCED 1249 - ER_TABLENAME_NOT_ALLOWED_HERE 1250 - ER_NOT_SUPPORTED_AUTH_MODE 1251 - ER_SPATIAL_CANT_HAVE_NULL 1252 - ER_COLLATION_CHARSET_MISMATCH 1253 - ER_SLAVE_WAS_RUNNING 1254 - ER_SLAVE_WAS_NOT_RUNNING 1255 - ER_TOO_BIG_FOR_UNCOMPRESS 1256 - ER_ZLIB_Z_MEM_ERROR 1257 - ER_ZLIB_Z_BUF_ERROR 1258 - ER_ZLIB_Z_DATA_ERROR 1259 - ER_CUT_VALUE_GROUP_CONCAT 1260 - ER_WARN_TOO_FEW_RECORDS 1261 - ER_WARN_TOO_MANY_RECORDS 1262 - ER_WARN_NULL_TO_NOTNULL 1263 - ER_WARN_DATA_OUT_OF_RANGE 1264 - WARN_DATA_TRUNCATED 1265 - ER_WARN_USING_OTHER_HANDLER 1266 - ER_CANT_AGGREGATE_2COLLATIONS 1267 - ER_DROP_USER 1268 - ER_REVOKE_GRANTS 1269 - ER_CANT_AGGREGATE_3COLLATIONS 1270 - ER_CANT_AGGREGATE_NCOLLATIONS 1271 - ER_VARIABLE_IS_NOT_STRUCT 1272 - ER_UNKNOWN_COLLATION 1273 - ER_SLAVE_IGNORED_SSL_PARAMS 1274 - ER_SERVER_IS_IN_SECURE_AUTH_MODE 1275 - ER_WARN_FIELD_RESOLVED 1276 - ER_BAD_SLAVE_UNTIL_COND 1277 - ER_MISSING_SKIP_SLAVE 1278 - ER_UNTIL_COND_IGNORED 1279 - ER_WRONG_NAME_FOR_INDEX 1280 - ER_WRONG_NAME_FOR_CATALOG 1281 - ER_WARN_QC_RESIZE 1282 - ER_BAD_FT_COLUMN 1283 - ER_UNKNOWN_KEY_CACHE 1284 - ER_WARN_HOSTNAME_WONT_WORK 1285 - ER_UNKNOWN_STORAGE_ENGINE 1286 - ER_WARN_DEPRECATED_SYNTAX 1287 - ER_NON_UPDATABLE_TABLE 1288 - ER_FEATURE_DISABLED 1289 - ER_OPTION_PREVENTS_STATEMENT 1290 - ER_DUPLICATED_VALUE_IN_TYPE 1291 - ER_TRUNCATED_WRONG_VALUE 1292 - ER_TOO_MUCH_AUTO_TIMESTAMP_COLS 1293 - ER_INVALID_ON_UPDATE 1294 - ER_UNSUPPORTED_PS 1295 - ER_GET_ERRMSG 1296 - ER_GET_TEMPORARY_ERRMSG 1297 - ER_UNKNOWN_TIME_ZONE 1298 - ER_WARN_INVALID_TIMESTAMP 1299 - ER_INVALID_CHARACTER_STRING 1300 - ER_WARN_ALLOWED_PACKET_OVERFLOWED 1301 - ER_CONFLICTING_DECLARATIONS 1302 - ER_SP_NO_RECURSIVE_CREATE 1303 - ER_SP_ALREADY_EXISTS 1304 - ER_SP_DOES_NOT_EXIST 1305 - ER_SP_DROP_FAILED 1306 - ER_SP_STORE_FAILED 1307 - ER_SP_LILABEL_MISMATCH 1308 - ER_SP_LABEL_REDEFINE 1309 - ER_SP_LABEL_MISMATCH 1310 - ER_SP_UNINIT_VAR 1311 - ER_SP_BADSELECT 1312 - ER_SP_BADRETURN 1313 - ER_SP_BADSTATEMENT 1314 - ER_UPDATE_LOG_DEPRECATED_IGNORED 1315 - ER_UPDATE_LOG_DEPRECATED_TRANSLATED 1316 - ER_QUERY_INTERRUPTED 1317 - ER_SP_WRONG_NO_OF_ARGS 1318 - ER_SP_COND_MISMATCH 1319 - ER_SP_NORETURN 1320 - ER_SP_NORETURNEND 1321 - ER_SP_BAD_CURSOR_QUERY 1322 - ER_SP_BAD_CURSOR_SELECT 1323 - ER_SP_CURSOR_MISMATCH 1324 - ER_SP_CURSOR_ALREADY_OPEN 1325 - ER_SP_CURSOR_NOT_OPEN 1326 - ER_SP_UNDECLARED_VAR 1327 - ER_SP_WRONG_NO_OF_FETCH_ARGS 1328 - ER_SP_FETCH_NO_DATA 1329 - ER_SP_DUP_PARAM 1330 - ER_SP_DUP_VAR 1331 - ER_SP_DUP_COND 1332 - ER_SP_DUP_CURS 1333 - ER_SP_CANT_ALTER 1334 - ER_SP_SUBSELECT_NYI 1335 - ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG 1336 - ER_SP_VARCOND_AFTER_CURSHNDLR 1337 - ER_SP_CURSOR_AFTER_HANDLER 1338 - ER_SP_CASE_NOT_FOUND 1339 - ER_FPARSER_TOO_BIG_FILE 1340 - ER_FPARSER_BAD_HEADER 1341 - ER_FPARSER_EOF_IN_COMMENT 1342 - ER_FPARSER_ERROR_IN_PARAMETER 1343 - ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER 1344 - ER_VIEW_NO_EXPLAIN 1345 - ER_FRM_UNKNOWN_TYPE 1346 - ER_WRONG_OBJECT 1347 - ER_NONUPDATEABLE_COLUMN 1348 - ER_VIEW_SELECT_DERIVED 1349 - ER_VIEW_SELECT_CLAUSE 1350 - ER_VIEW_SELECT_VARIABLE 1351 - ER_VIEW_SELECT_TMPTABLE 1352 - ER_VIEW_WRONG_LIST 1353 - ER_WARN_VIEW_MERGE 1354 - ER_WARN_VIEW_WITHOUT_KEY 1355 - ER_VIEW_INVALID 1356 - ER_SP_NO_DROP_SP 1357 - ER_SP_GOTO_IN_HNDLR 1358 - ER_TRG_ALREADY_EXISTS 1359 - ER_TRG_DOES_NOT_EXIST 1360 - ER_TRG_ON_VIEW_OR_TEMP_TABLE 1361 - ER_TRG_CANT_CHANGE_ROW 1362 - ER_TRG_NO_SUCH_ROW_IN_TRG 1363 - ER_NO_DEFAULT_FOR_FIELD 1364 - ER_DIVISION_BY_ZERO 1365 - ER_TRUNCATED_WRONG_VALUE_FOR_FIELD 1366 - ER_ILLEGAL_VALUE_FOR_TYPE 1367 - ER_VIEW_NONUPD_CHECK 1368 - ER_VIEW_CHECK_FAILED 1369 - ER_PROCACCESS_DENIED_ERROR 1370 - ER_RELAY_LOG_FAIL 1371 - ER_PASSWD_LENGTH 1372 - ER_UNKNOWN_TARGET_BINLOG 1373 - ER_IO_ERR_LOG_INDEX_READ 1374 - ER_BINLOG_PURGE_PROHIBITED 1375 - ER_FSEEK_FAIL 1376 - ER_BINLOG_PURGE_FATAL_ERR 1377 - ER_LOG_IN_USE 1378 - ER_LOG_PURGE_UNKNOWN_ERR 1379 - ER_RELAY_LOG_INIT 1380 - ER_NO_BINARY_LOGGING 1381 - ER_RESERVED_SYNTAX 1382 - ER_WSAS_FAILED 1383 - ER_DIFF_GROUPS_PROC 1384 - ER_NO_GROUP_FOR_PROC 1385 - ER_ORDER_WITH_PROC 1386 - ER_LOGGING_PROHIBIT_CHANGING_OF 1387 - ER_NO_FILE_MAPPING 1388 - ER_WRONG_MAGIC 1389 - ER_PS_MANY_PARAM 1390 - ER_KEY_PART_0 1391 - ER_VIEW_CHECKSUM 1392 - ER_VIEW_MULTIUPDATE 1393 - ER_VIEW_NO_INSERT_FIELD_LIST 1394 - ER_VIEW_DELETE_MERGE_VIEW 1395 - ER_CANNOT_USER 1396 - ER_XAER_NOTA 1397 - ER_XAER_INVAL 1398 - ER_XAER_RMFAIL 1399 - ER_XAER_OUTSIDE 1400 - ER_XAER_RMERR 1401 - ER_XA_RBROLLBACK 1402 - ER_NONEXISTING_PROC_GRANT 1403 - ER_PROC_AUTO_GRANT_FAIL 1404 - ER_PROC_AUTO_REVOKE_FAIL 1405 - ER_DATA_TOO_LONG 1406 - ER_SP_BAD_SQLSTATE 1407 - ER_STARTUP 1408 - ER_LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR 1409 - ER_CANT_CREATE_USER_WITH_GRANT 1410 - ER_WRONG_VALUE_FOR_TYPE 1411 - ER_TABLE_DEF_CHANGED 1412 - ER_SP_DUP_HANDLER 1413 - ER_SP_NOT_VAR_ARG 1414 - ER_SP_NO_RETSET 1415 - ER_CANT_CREATE_GEOMETRY_OBJECT 1416 - ER_FAILED_ROUTINE_BREAK_BINLOG 1417 - ER_BINLOG_UNSAFE_ROUTINE 1418 - ER_BINLOG_CREATE_ROUTINE_NEED_SUPER 1419 - ER_EXEC_STMT_WITH_OPEN_CURSOR 1420 - ER_STMT_HAS_NO_OPEN_CURSOR 1421 - ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG 1422 - ER_NO_DEFAULT_FOR_VIEW_FIELD 1423 - ER_SP_NO_RECURSION 1424 - ER_TOO_BIG_SCALE 1425 - ER_TOO_BIG_PRECISION 1426 - ER_M_BIGGER_THAN_D 1427 - ER_WRONG_LOCK_OF_SYSTEM_TABLE 1428 - ER_CONNECT_TO_FOREIGN_DATA_SOURCE 1429 - ER_QUERY_ON_FOREIGN_DATA_SOURCE 1430 - ER_FOREIGN_DATA_SOURCE_DOESNT_EXIST 1431 - ER_FOREIGN_DATA_STRING_INVALID_CANT_CREATE 1432 - ER_FOREIGN_DATA_STRING_INVALID 1433 - ER_CANT_CREATE_FEDERATED_TABLE 1434 - ER_TRG_IN_WRONG_SCHEMA 1435 - ER_STACK_OVERRUN_NEED_MORE 1436 - ER_TOO_LONG_BODY 1437 - ER_WARN_CANT_DROP_DEFAULT_KEYCACHE 1438 - ER_TOO_BIG_DISPLAYWIDTH 1439 - ER_XAER_DUPID 1440 - ER_DATETIME_FUNCTION_OVERFLOW 1441 - ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG 1442 - ER_VIEW_PREVENT_UPDATE 1443 - ER_PS_NO_RECURSION 1444 - ER_SP_CANT_SET_AUTOCOMMIT 1445 - ER_MALFORMED_DEFINER 1446 - ER_VIEW_FRM_NO_USER 1447 - ER_VIEW_OTHER_USER 1448 - ER_NO_SUCH_USER 1449 - ER_FORBID_SCHEMA_CHANGE 1450 - ER_ROW_IS_REFERENCED_2 1451 - ER_NO_REFERENCED_ROW_2 1452 - ER_SP_BAD_VAR_SHADOW 1453 - ER_TRG_NO_DEFINER 1454 - ER_OLD_FILE_FORMAT 1455 - ER_SP_RECURSION_LIMIT 1456 - ER_SP_PROC_TABLE_CORRUPT 1457 - ER_SP_WRONG_NAME 1458 - ER_TABLE_NEEDS_UPGRADE 1459 - ER_SP_NO_AGGREGATE 1460 - ER_MAX_PREPARED_STMT_COUNT_REACHED 1461 - ER_VIEW_RECURSIVE 1462 - ER_NON_GROUPING_FIELD_USED 1463 - ER_TABLE_CANT_HANDLE_SPKEYS 1464 - ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA 1465 - ER_REMOVED_SPACES 1466 - ER_AUTOINC_READ_FAILED 1467 - ER_USERNAME 1468 - ER_HOSTNAME 1469 - ER_WRONG_STRING_LENGTH 1470 - ER_NON_INSERTABLE_TABLE 1471 - ER_ADMIN_WRONG_MRG_TABLE 1472 - ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT 1473 - ER_NAME_BECOMES_EMPTY 1474 - ER_AMBIGUOUS_FIELD_TERM 1475 - ER_FOREIGN_SERVER_EXISTS 1476 - ER_FOREIGN_SERVER_DOESNT_EXIST 1477 - ER_ILLEGAL_HA_CREATE_OPTION 1478 - ER_PARTITION_REQUIRES_VALUES_ERROR 1479 - ER_PARTITION_WRONG_VALUES_ERROR 1480 - ER_PARTITION_MAXVALUE_ERROR 1481 - ER_PARTITION_SUBPARTITION_ERROR 1482 - ER_PARTITION_SUBPART_MIX_ERROR 1483 - ER_PARTITION_WRONG_NO_PART_ERROR 1484 - ER_PARTITION_WRONG_NO_SUBPART_ERROR 1485 - ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR 1486 - ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR 1487 - ER_FIELD_NOT_FOUND_PART_ERROR 1488 - ER_LIST_OF_FIELDS_ONLY_IN_HASH_ERROR 1489 - ER_INCONSISTENT_PARTITION_INFO_ERROR 1490 - ER_PARTITION_FUNC_NOT_ALLOWED_ERROR 1491 - ER_PARTITIONS_MUST_BE_DEFINED_ERROR 1492 - ER_RANGE_NOT_INCREASING_ERROR 1493 - ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR 1494 - ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR 1495 - ER_PARTITION_ENTRY_ERROR 1496 - ER_MIX_HANDLER_ERROR 1497 - ER_PARTITION_NOT_DEFINED_ERROR 1498 - ER_TOO_MANY_PARTITIONS_ERROR 1499 - ER_SUBPARTITION_ERROR 1500 - ER_CANT_CREATE_HANDLER_FILE 1501 - ER_BLOB_FIELD_IN_PART_FUNC_ERROR 1502 - ER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF 1503 - ER_NO_PARTS_ERROR 1504 - ER_PARTITION_MGMT_ON_NONPARTITIONED 1505 - ER_FOREIGN_KEY_ON_PARTITIONED 1506 - ER_DROP_PARTITION_NON_EXISTENT 1507 - ER_DROP_LAST_PARTITION 1508 - ER_COALESCE_ONLY_ON_HASH_PARTITION 1509 - ER_REORG_HASH_ONLY_ON_SAME_NO 1510 - ER_REORG_NO_PARAM_ERROR 1511 - ER_ONLY_ON_RANGE_LIST_PARTITION 1512 - ER_ADD_PARTITION_SUBPART_ERROR 1513 - ER_ADD_PARTITION_NO_NEW_PARTITION 1514 - ER_COALESCE_PARTITION_NO_PARTITION 1515 - ER_REORG_PARTITION_NOT_EXIST 1516 - ER_SAME_NAME_PARTITION 1517 - ER_NO_BINLOG_ERROR 1518 - ER_CONSECUTIVE_REORG_PARTITIONS 1519 - ER_REORG_OUTSIDE_RANGE 1520 - ER_PARTITION_FUNCTION_FAILURE 1521 - ER_PART_STATE_ERROR 1522 - ER_LIMITED_PART_RANGE 1523 - ER_PLUGIN_IS_NOT_LOADED 1524 - ER_WRONG_VALUE 1525 - ER_NO_PARTITION_FOR_GIVEN_VALUE 1526 - ER_FILEGROUP_OPTION_ONLY_ONCE 1527 - ER_CREATE_FILEGROUP_FAILED 1528 - ER_DROP_FILEGROUP_FAILED 1529 - ER_TABLESPACE_AUTO_EXTEND_ERROR 1530 - ER_WRONG_SIZE_NUMBER 1531 - ER_SIZE_OVERFLOW_ERROR 1532 - ER_ALTER_FILEGROUP_FAILED 1533 - ER_BINLOG_ROW_LOGGING_FAILED 1534 - ER_BINLOG_ROW_WRONG_TABLE_DEF 1535 - ER_BINLOG_ROW_RBR_TO_SBR 1536 - ER_EVENT_ALREADY_EXISTS 1537 - ER_EVENT_STORE_FAILED 1538 - ER_EVENT_DOES_NOT_EXIST 1539 - ER_EVENT_CANT_ALTER 1540 - ER_EVENT_DROP_FAILED 1541 - ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG 1542 - ER_EVENT_ENDS_BEFORE_STARTS 1543 - ER_EVENT_EXEC_TIME_IN_THE_PAST 1544 - ER_EVENT_OPEN_TABLE_FAILED 1545 - ER_EVENT_NEITHER_M_EXPR_NOR_M_AT 1546 - ER_COL_COUNT_DOESNT_MATCH_CORRUPTED 1547 - ER_CANNOT_LOAD_FROM_TABLE 1548 - ER_EVENT_CANNOT_DELETE 1549 - ER_EVENT_COMPILE_ERROR 1550 - ER_EVENT_SAME_NAME 1551 - ER_EVENT_DATA_TOO_LONG 1552 - ER_DROP_INDEX_FK 1553 - ER_WARN_DEPRECATED_SYNTAX_WITH_VER 1554 - ER_CANT_WRITE_LOCK_LOG_TABLE 1555 - ER_CANT_LOCK_LOG_TABLE 1556 - ER_FOREIGN_DUPLICATE_KEY 1557 - ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE 1558 - ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR 1559 - ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT 1560 - ER_NDB_CANT_SWITCH_BINLOG_FORMAT 1561 - ER_PARTITION_NO_TEMPORARY 1562 - ER_PARTITION_CONST_DOMAIN_ERROR 1563 - ER_PARTITION_FUNCTION_IS_NOT_ALLOWED 1564 - ER_DDL_LOG_ERROR 1565 - ER_NULL_IN_VALUES_LESS_THAN 1566 - ER_WRONG_PARTITION_NAME 1567 - ER_CANT_CHANGE_TX_ISOLATION 1568 - ER_DUP_ENTRY_AUTOINCREMENT_CASE 1569 - ER_EVENT_MODIFY_QUEUE_ERROR 1570 - ER_EVENT_SET_VAR_ERROR 1571 - ER_PARTITION_MERGE_ERROR 1572 - ER_CANT_ACTIVATE_LOG 1573 - ER_RBR_NOT_AVAILABLE 1574 - ER_BASE64_DECODE_ERROR 1575 - ER_EVENT_RECURSION_FORBIDDEN 1576 - ER_EVENTS_DB_ERROR 1577 - ER_ONLY_INTEGERS_ALLOWED 1578 - ER_UNSUPORTED_LOG_ENGINE 1579 - ER_BAD_LOG_STATEMENT 1580 - ER_CANT_RENAME_LOG_TABLE 1581 - ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT 1582 - ER_WRONG_PARAMETERS_TO_NATIVE_FCT 1583 - ER_WRONG_PARAMETERS_TO_STORED_FCT 1584 - ER_NATIVE_FCT_NAME_COLLISION 1585 - ER_DUP_ENTRY_WITH_KEY_NAME 1586 - ER_BINLOG_PURGE_EMFILE 1587 - ER_EVENT_CANNOT_CREATE_IN_THE_PAST 1588 - ER_EVENT_CANNOT_ALTER_IN_THE_PAST 1589 - ER_SLAVE_INCIDENT 1590 - ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT 1591 - ER_BINLOG_UNSAFE_STATEMENT 1592 - ER_SLAVE_FATAL_ERROR 1593 - ER_SLAVE_RELAY_LOG_READ_FAILURE 1594 - ER_SLAVE_RELAY_LOG_WRITE_FAILURE 1595 - ER_SLAVE_CREATE_EVENT_FAILURE 1596 - ER_SLAVE_MASTER_COM_FAILURE 1597 - ER_BINLOG_LOGGING_IMPOSSIBLE 1598 - ER_VIEW_NO_CREATION_CTX 1599 - ER_VIEW_INVALID_CREATION_CTX 1600 - ER_SR_INVALID_CREATION_CTX 1601 - ER_TRG_CORRUPTED_FILE 1602 - ER_TRG_NO_CREATION_CTX 1603 - ER_TRG_INVALID_CREATION_CTX 1604 - ER_EVENT_INVALID_CREATION_CTX 1605 - ER_TRG_CANT_OPEN_TABLE 1606 - ER_CANT_CREATE_SROUTINE 1607 - ER_NEVER_USED 1608 - ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT 1609 - ER_SLAVE_CORRUPT_EVENT 1610 - ER_LOAD_DATA_INVALID_COLUMN 1611 - ER_LOG_PURGE_NO_FILE 1612 - ER_XA_RBTIMEOUT 1613 - ER_XA_RBDEADLOCK 1614 - ER_NEED_REPREPARE 1615 - ER_DELAYED_NOT_SUPPORTED 1616 - WARN_NO_MASTER_INFO 1617 - WARN_OPTION_IGNORED 1618 - WARN_PLUGIN_DELETE_BUILTIN 1619 - WARN_PLUGIN_BUSY 1620 - ER_VARIABLE_IS_READONLY 1621 - ER_WARN_ENGINE_TRANSACTION_ROLLBACK 1622 - ER_SLAVE_HEARTBEAT_FAILURE 1623 - ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE 1624 - ER_NDB_REPLICATION_SCHEMA_ERROR 1625 - ER_CONFLICT_FN_PARSE_ERROR 1626 - ER_EXCEPTIONS_WRITE_ERROR 1627 - ER_TOO_LONG_TABLE_COMMENT 1628 - ER_TOO_LONG_FIELD_COMMENT 1629 - ER_FUNC_INEXISTENT_NAME_COLLISION 1630 - ER_DATABASE_NAME 1631 - ER_TABLE_NAME 1632 - ER_PARTITION_NAME 1633 - ER_SUBPARTITION_NAME 1634 - ER_TEMPORARY_NAME 1635 - ER_RENAMED_NAME 1636 - ER_TOO_MANY_CONCURRENT_TRXS 1637 - WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED 1638 - ER_DEBUG_SYNC_TIMEOUT 1639 - ER_DEBUG_SYNC_HIT_LIMIT 1640 - ER_DUP_SIGNAL_SET 1641 - ER_SIGNAL_WARN 1642 - ER_SIGNAL_NOT_FOUND 1643 - ER_SIGNAL_EXCEPTION 1644 - ER_RESIGNAL_WITHOUT_ACTIVE_HANDLER 1645 - ER_SIGNAL_BAD_CONDITION_TYPE 1646 - WARN_COND_ITEM_TRUNCATED 1647 - ER_COND_ITEM_TOO_LONG 1648 - ER_UNKNOWN_LOCALE 1649 - ER_SLAVE_IGNORE_SERVER_IDS 1650 - ER_QUERY_CACHE_DISABLED 1651 - ER_SAME_NAME_PARTITION_FIELD 1652 - ER_PARTITION_COLUMN_LIST_ERROR 1653 - ER_WRONG_TYPE_COLUMN_VALUE_ERROR 1654 - ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR 1655 - ER_MAXVALUE_IN_VALUES_IN 1656 - ER_TOO_MANY_VALUES_ERROR 1657 - ER_ROW_SINGLE_PARTITION_FIELD_ERROR 1658 - ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD 1659 - ER_PARTITION_FIELDS_TOO_LONG 1660 - ER_BINLOG_ROW_ENGINE_AND_STMT_ENGINE 1661 - ER_BINLOG_ROW_MODE_AND_STMT_ENGINE 1662 - ER_BINLOG_UNSAFE_AND_STMT_ENGINE 1663 - ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE 1664 - ER_BINLOG_STMT_MODE_AND_ROW_ENGINE 1665 - ER_BINLOG_ROW_INJECTION_AND_STMT_MODE 1666 - ER_BINLOG_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE 1667 - ER_BINLOG_UNSAFE_LIMIT 1668 - ER_BINLOG_UNSAFE_INSERT_DELAYED 1669 - ER_BINLOG_UNSAFE_SYSTEM_TABLE 1670 - ER_BINLOG_UNSAFE_AUTOINC_COLUMNS 1671 - ER_BINLOG_UNSAFE_UDF 1672 - ER_BINLOG_UNSAFE_SYSTEM_VARIABLE 1673 - ER_BINLOG_UNSAFE_SYSTEM_FUNCTION 1674 - ER_BINLOG_UNSAFE_NONTRANS_AFTER_TRANS 1675 - ER_MESSAGE_AND_STATEMENT 1676 - ER_SLAVE_CONVERSION_FAILED 1677 - ER_SLAVE_CANT_CREATE_CONVERSION 1678 - ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT 1679 - ER_PATH_LENGTH 1680 - ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT 1681 - ER_WRONG_NATIVE_TABLE_STRUCTURE 1682 - ER_WRONG_PERFSCHEMA_USAGE 1683 - ER_WARN_I_S_SKIPPED_TABLE 1684 - ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT 1685 - ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_DIRECT 1686 - ER_SPATIAL_MUST_HAVE_GEOM_COL 1687 - ER_TOO_LONG_INDEX_COMMENT 1688 - ER_LOCK_ABORTED 1689 - ER_DATA_OUT_OF_RANGE 1690 - ER_WRONG_SPVAR_TYPE_IN_LIMIT 1691 - ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE 1692 - ER_BINLOG_UNSAFE_MIXED_STATEMENT 1693 - ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN 1694 - ER_STORED_FUNCTION_PREVENTS_SWITCH_SQL_LOG_BIN 1695 - ER_FAILED_READ_FROM_PAR_FILE 1696 - ER_VALUES_IS_NOT_INT_TYPE_ERROR 1697 - ER_ACCESS_DENIED_NO_PASSWORD_ERROR 1698 - ER_SET_PASSWORD_AUTH_PLUGIN 1699 - ER_GRANT_PLUGIN_USER_EXISTS 1700 - ER_TRUNCATE_ILLEGAL_FK 1701 - ER_PLUGIN_IS_PERMANENT 1702 - ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MIN 1703 - ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX 1704 - ER_STMT_CACHE_FULL 1705 - ER_MULTI_UPDATE_KEY_CONFLICT 1706 - ER_TABLE_NEEDS_REBUILD 1707 - WARN_OPTION_BELOW_LIMIT 1708 - ER_INDEX_COLUMN_TOO_LONG 1709 - ER_ERROR_IN_TRIGGER_BODY 1710 - ER_ERROR_IN_UNKNOWN_TRIGGER_BODY 1711 - ER_INDEX_CORRUPT 1712 - ER_UNDO_RECORD_TOO_BIG 1713 - ER_BINLOG_UNSAFE_INSERT_IGNORE_SELECT 1714 - ER_BINLOG_UNSAFE_INSERT_SELECT_UPDATE 1715 - ER_BINLOG_UNSAFE_REPLACE_SELECT 1716 - ER_BINLOG_UNSAFE_CREATE_IGNORE_SELECT 1717 - ER_BINLOG_UNSAFE_CREATE_REPLACE_SELECT 1718 - ER_BINLOG_UNSAFE_UPDATE_IGNORE 1719 - ER_PLUGIN_NO_UNINSTALL 1720 - ER_PLUGIN_NO_INSTALL 1721 - ER_BINLOG_UNSAFE_WRITE_AUTOINC_SELECT 1722 - ER_BINLOG_UNSAFE_CREATE_SELECT_AUTOINC 1723 - ER_BINLOG_UNSAFE_INSERT_TWO_KEYS 1724 - ER_TABLE_IN_FK_CHECK 1725 - ER_UNSUPPORTED_ENGINE 1726 - ER_BINLOG_UNSAFE_AUTOINC_NOT_FIRST 1727 - ER_ERROR_LAST 1727 + Name: 'mysql + Type: 'module + Exports: [connect-sql send-sql sql-escape to-sql-binary to-sql mysql-map-rebol-values] + Authors: [ + "Nenad Rakocevic / SOFTINNOV " + "Shixin Zeng " + "Oldes" + ] + Web: http://softinnov.org/rebol/mysql.shtml + Date: 27-May-2020 + File: %prot-mysql.r + Version: 2.1.0 + History: [ + 1.3.1 "Nenad Rakocevic" "Rebol2 original version" + 2.0.0 "Shixin Zeng" "Rebol3 async version" + 2.1.0 "Oldes" "Including it in Rebol3 source code as a module" + ] + References: [ + http://softinnov.org/rebol/mysql.shtml + https://github.com/zsx/mysql-r3 + ] + Notes: { + Old "native_password" authentication is required so far (with MySQL 8.0). + For details how to enable it see: https://stackoverflow.com/a/50131831/494472 + } ] -either all [value? 'mysql-debug? mysql-debug?] [ - debug: :print -][ - debug: :comment -] +append system/options/log [mysql: 1] -mysql-driver: make object![ +mysql-driver: make object! [ sql-buffer: make string! 1024 not-squote: complement charset "'" not-dquote: complement charset {"} copy*: get in system/contexts/lib 'copy - insert*: get in system/contexts/lib 'insert + insert*: get in system/contexts/lib 'insert close*: get in system/contexts/lib 'close std-header-length: 4 std-comp-header-length: 3 end-marker: 254 + change-type-handler: none ;------ Internals -------- defs: compose/deep [ @@ -1002,7 +284,7 @@ mysql-driver: make object![ string [to string!] geometry [to string!] ] - + set 'change-type-handler func [p [port!] type [word!] blk [block!]][ head change/only next find p/locals/conv-list type blk ] @@ -1012,19 +294,19 @@ mysql-driver: make object![ rows [block!] /local row i convert-body action cols col conv-func tmp ][ - ;;debug ["converting types"] + ;;sys/log/more 'MySQL["converting types"] cols: p/locals/current-result/columns convert-body: make block! 1 action: [if tmp: pick row (i)] foreach col cols [ i: index? find cols col if 'none <> conv-func: select p/locals/conv-list col/type [ - ;;debug ["conv-func:" mold conv-func "for" col/type] + ;;sys/log/more 'MySQL["conv-func:" mold conv-func "for" col/type] append convert-body append/only compose action head insert* at compose [change at row (i) :tmp] 5 conv-func ] ] - ;;debug ["convert-body:" mold convert-body] + ;;sys/log/more 'MySQL["convert-body:" mold convert-body] if not empty? convert-body [ either p/locals/result-options/flat? [ while [not tail? rows][ @@ -1129,12 +411,12 @@ mysql-driver: make object![ mark: insert* remove mark either tail? args ["NULL"][to-sql args/1] if not tail? args [args: next args] ] - ;debug sql + ;sys/log/more 'MySQL sql sql ] show-server: func [obj [object!]][ - debug [ newline + sys/log/more 'MySQL[ newline "----- Server ------" newline "Version:" obj/version newline "Protocol version:" obj/protocol newline @@ -1167,7 +449,7 @@ mysql-driver: make object![ nr: 1345345333x1 nr2: 7x1 foreach byte data [ - if all [byte <> #" " byte <> #"^(tab)"][ + if all [byte <> #" " byte <> #"^-"][ byte: to-pair to-integer byte nr: xor-pair nr (((and-pair 63x1 nr) + nr2) * byte) + (nr * 256x1) nr2: nr2 + byte @@ -1181,7 +463,7 @@ mysql-driver: make object![ adding: 7x1 nr2: to-pair to-integer #12345671 foreach byte data [ - if all [byte <> #" " byte <> #"^(tab)"][ + if all [byte <> #" " byte <> #"^-"][ byte: to-pair to-integer byte nr: xor-pair nr (((and-pair 63x1 nr) + adding) * byte) + (nr * 256x1) nr2: nr2 + xor-pair nr (nr2 * 256x1) @@ -1347,7 +629,7 @@ mysql-driver: make object![ write-string: func [value [string! none! binary!] /local t][ if none? value [return make binary! 0] - ;debug ["writing a string:" mold value] + ;sys/log/more 'MySQL["writing a string:" mold value] to-binary join value to char! 0 ] @@ -1360,9 +642,9 @@ mysql-driver: make object![ insert data header data: skip data 16777215 + length? header ] - ;;debug ["write function port state " open? tcp-port] + ;;sys/log/more 'MySQL["write function port state " open? tcp-port] ;if not open? tcp-port [open tcp-port] - ;debug ["state:" tcp-port/locals/state] + ;sys/log/more 'MySQL["state:" tcp-port/locals/state] header: join write-int24 length? data write-byte port/locals/seq-num: port/locals/seq-num + 1 @@ -1378,7 +660,7 @@ mysql-driver: make object![ send-cmd: func [port [port!] cmd [integer!] cmd-data] compose/deep [ port/locals/seq-num: -1 port/locals/current-cmd: cmd - ;debug ["sending cmd:" cmd] + ;sys/log/more 'MySQL["sending cmd:" cmd] send-packet port rejoin [ write-byte cmd port/locals/current-cmd-data: @@ -1400,12 +682,12 @@ mysql-driver: make object![ ] ][either string? cmd-data [cmd-data][pick cmd-data 1]] ] - ;debug ["sent a command"] + ;sys/log/more 'MySQL["sent a command"] port/locals/state: 'sending-cmd ] insert-query: func [port [port!] data [string! block!]][ - debug ["insert-query:" data] + sys/log/more 'MySQL["insert-query:" data] send-cmd port defs/cmd/query data none ] @@ -1415,8 +697,8 @@ mysql-driver: make object![ parse/all s: data [ any [ #"#" thru newline - | #"'" any ["\\" | "\'" | "''" | not-squote] #"'" - |{"} any [{\"} | {""} | not-dquote] {"} + | #"'" any ["\\" | "\'" | "''" | not-squote] #"'" + | #"^"" any [{\"} | {""} | not-dquote] #"^"" | #"`" thru #"`" | "begin" thru "end" | e: d ( @@ -1432,7 +714,7 @@ mysql-driver: make object![ ] insert-cmd: func [port [port!] data [block!] /local type][ - ;debug ["inserting cmd:" mold data] + ;sys/log/more 'MySQL["inserting cmd:" mold data] type: select defs/cmd data/1 either type [ send-cmd port type next data @@ -1443,11 +725,11 @@ mysql-driver: make object![ parse-a-packet: func [ port [port!] - /local pl status + /local pl status rules ][ pl: port/locals - ;debug ["parsing a packet:" mold port/data] + sys/log/debug 'MySQL["parsing a packet:" mold port/data] pl/last-status: status: to integer! port/data/1 pl/error-code: pl/error-msg: none @@ -1472,7 +754,8 @@ mysql-driver: make object![ [read-string (pl/error-msg: string)] ] ] - cause-error 'user 'message reduce [port pl/error-code pl/error-msg] + pl/state: 'idle + cause-error 'mysql 'message reduce [pl/error-code pl/error-msg] return 'ERR ] 254 [ @@ -1531,9 +814,10 @@ mysql-driver: make object![ ][ pl: port/locals mysql-port: pl/mysql-port + sys/log/more 'MySQL ["Event:^[[22m" evt-type] case compose [ (evt-type = 'read) [ - debug ["emitting result (" length? pl/results ")"] + sys/log/more 'MySQL["emitting result (" length? pl/results ")"] mysql-port/data: convert-results port pl/results pl/result-options append system/ports/system make event! [type: evt-type port: mysql-port] ] @@ -1545,7 +829,7 @@ mysql-driver: make object![ append system/ports/system make event! [type: evt-type port: mysql-port] ] ][ - cause-error 'user 'message reduce [rejoin ["Unsupported event: " type]] + cause-error 'user 'message rejoin ["Unsupported event: " type] ] ] @@ -1564,14 +848,14 @@ mysql-driver: make object![ ][ pl: port/locals mysql-port: pl/mysql-port - debug ["processing a packet in state:" pl/state] - debug ["buf:" mold buf] + sys/log/more 'MySQL["processing a packet in state:" pl/state] + sys/log/debug 'MySQL["buf:" mold buf] switch pl/state [ reading-greeting [ process-greeting-packet port buf send-packet port pack-auth-packet port pl/state: 'sending-auth-pack - debug ["state changed to sending-auth-pack"] + sys/log/more 'MySQL["state changed to sending-auth-pack"] pl/stream-end?: true ;wait for a WROTE event ] @@ -1580,19 +864,19 @@ mysql-driver: make object![ ;switch to old password mode send-packet port write-string scramble/v10 port/pass port pl/state: 'sending-old-auth-pack - debug ["state changed to sending-old-auth-pack"] + sys/log/more 'MySQL["state changed to sending-old-auth-pack"] ][ if buf/1 = 255 [;error packet parse/all skip buf 1 [ - read-int (pl/error-code: int) + read-int (pl/error-code: int) read-string (pl/error-msg: string) ] - cause-error 'Access 'cannot-open reduce [port pl/error-msg pl/error-code] + cause-error 'mysql 'message reduce [pl/error-code pl/error-msg ] ] - ;debug ["handshaked"] + sys/log/more 'MySQL "handshaked" ;OK? emit-event port 'connect - ;debug ["o-buf after auth resp:" mold port/locals/o-buf] + ;sys/log/more 'MySQL["o-buf after auth resp:" mold port/locals/o-buf] start-next-cmd port ] pl/stream-end?: true ;done or wait for a WROTE event @@ -1602,7 +886,7 @@ mysql-driver: make object![ if buf/1 = #"^(00)"[ emit-event port 'connect - ;debug ["o-buf after old auth resp:" mold port/locals/o-buf] + ;sys/log/more 'MySQL["o-buf after old auth resp:" mold port/locals/o-buf] start-next-cmd port ] pl/stream-end?: true ;done or wait for a WROTE event @@ -1610,7 +894,7 @@ mysql-driver: make object![ reading-cmd-resp [;reading a response ;check if we've got enough data - debug ["read a cmd response for" pl/current-cmd] + sys/log/more 'MySQL["read a cmd response for" pl/current-cmd] switch/default parse-a-packet port [ OTHER [ case [ @@ -1619,9 +903,9 @@ mysql-driver: make object![ parse/all/case buf [ read-length (if zero? pl/current-result/n-columns: len [ pl/stream-end?: true - debug ["stream ended because of 0 columns"] + sys/log/more 'MySQL["stream ended because of 0 columns"] ] - debug ["Read number of columns:" len] + sys/log/more 'MySQL["Read number of columns:" len] ) ] pl/state: 'reading-fields @@ -1637,7 +921,7 @@ mysql-driver: make object![ append pl/results pl/current-result either pl/stream-end? [ emit-event port 'read - debug ["Stream ended by an OK packet"] + sys/log/more 'MySQL["Stream ended by an OK packet"] start-next-cmd port exit ][ @@ -1669,7 +953,7 @@ mysql-driver: make object![ ][ cause-error 'user 'message reduce ["Unexpected number of fields" pl] ] - debug ["stream-end? after reading-cmd-resp:" pl/stream-end?] + sys/log/more 'MySQL["stream-end? after reading-cmd-resp:" pl/stream-end?] ] reading-fields [ @@ -1716,7 +1000,7 @@ mysql-driver: make object![ if none? pl/current-result/columns [ pl/current-result/columns: make block! pl/current-result/n-columns ] - ;debug ["read a column: " col/name] + ;sys/log/more 'MySQL["read a column: " col/name] append pl/current-result/columns :col pl/state: 'reading-fields ] @@ -1726,7 +1010,7 @@ mysql-driver: make object![ pl/state: 'reading-rows ] (pl/current-cmd = defs/cmd/field-list) [ - debug ["result ended for field-list"] + sys/log/more 'MySQL["result ended for field-list"] pl/current-result/query-finish-time: now/precise append pl/results pl/current-result pl/stream-end?: not pl/more-results? @@ -1759,9 +1043,9 @@ mysql-driver: make object![ switch/default pkt-type [ OTHER FB[ row: make block! pl/current-result/n-columns - ;debug ["row buf:" copy/part buf pl/next-packet-length] + ;sys/log/more 'MySQL["row buf:" copy/part buf pl/next-packet-length] parse/all/case buf [pl/current-result/n-columns [read-field (append row field)]] - ;debug ["row:" mold row] + ;sys/log/more 'MySQL["row:" mold row] if none? pl/current-result/rows [ pl/current-result/rows: make block! 10 ] @@ -1783,31 +1067,31 @@ mysql-driver: make object![ ] ] pl/current-result/query-finish-time: now/precise - debug ["Length of rows in current result:" length? pl/current-result/rows] + sys/log/more 'MySQL["Length of rows in current result:" length? pl/current-result/rows] append pl/results pl/current-result - ;debug ["results length: " length? pl/results] + ;sys/log/more 'MySQL["results length: " length? pl/results] either pl/more-results? [ pl/stream-end?: false pl/state: 'reading-cmd-resp pl/current-result: make result-class [query-start-time: pl/query-start-time] ;get ready for next result set ][ pl/stream-end?: true - debug ["Emitting read event because of no more results"] + sys/log/more 'MySQL["Emitting read event because of no more results"] emit-event port 'read - ;debug ["o-buf after reading query resp:" mold port/locals/o-buf] + ;sys/log/more 'MySQL["o-buf after reading query resp:" mold port/locals/o-buf] start-next-cmd port exit ] ] ][ - ;debug ["unexpected row" mold pl] + ;sys/log/more 'MySQL["unexpected row" mold pl] cause-error 'user 'message reduce ["Unexpected row" pl] ] - ;debug ["stream-end? after reading-rows:" pl/stream-end?] + ;sys/log/more 'MySQL["stream-end? after reading-rows:" pl/stream-end?] ] idle [ - debug ["unprocessed message from server" tcp-port/data] + sys/log/more 'MySQL["unprocessed message from server" tcp-port/data] break ] ][ @@ -1821,7 +1105,7 @@ mysql-driver: make object![ data [binary!] /local pl tcp-port feature-supported? ][ - debug ["processing a greeting packet"] + sys/log/more 'MySQL["processing a greeting packet"] tcp-port: port pl: port/locals if data/1 = 255 [;error packet @@ -1907,7 +1191,7 @@ mysql-driver: make object![ ] ] - ;debug ["auth-pack:" mold auth-pack] + ;sys/log/more 'MySQL["auth-pack:" mold auth-pack] auth-pack ] @@ -1929,9 +1213,9 @@ mysql-driver: make object![ pl: tcp-port/locals pl/last-activity: now/precise - debug ["tcp event:" event/type] - ;debug ["o-buf:" mold tcp-port/locals/o-buf] - ;;debug ["locals:" mold tcp-port/locals] + sys/log/more 'MySQL["tcp event:" event/type] + ;sys/log/more 'MySQL["o-buf:" mold tcp-port/locals/o-buf] + ;;sys/log/more 'MySQL["locals:" mold tcp-port/locals] ;pl/exit-wait?: false switch event/type [ error [ @@ -1939,11 +1223,11 @@ mysql-driver: make object![ return true ] lookup [ - ;;debug "loop up" + ;;sys/log/more 'MySQL"loop up" open tcp-port ] connect [ - ;;debug "connect" + ;;sys/log/more 'MySQL"connect" read tcp-port ;greeting from server pl/packet-state: 'reading-packet-head pl/next-packet-length: std-header-length @@ -1951,34 +1235,34 @@ mysql-driver: make object![ pl/stream-end?: false ] read [ - ;;debug "read event" - debug ["buffer:" mold tcp-port/data] - debug ["current buffer length:" length? tcp-port/data] - ;debug ["buffer with data:" mold tcp-port/data] + ;;sys/log/more 'MySQL"read event" + sys/log/debug 'MySQL["buffer:" mold tcp-port/data] + sys/log/more 'MySQL["current buffer length:" length? tcp-port/data] + ;sys/log/more 'MySQL["buffer with data:" mold tcp-port/data] while [true] [ - debug ["next-len:" pl/next-packet-length ", buf: " length? tcp-port/data] + sys/log/more 'MySQL["next-len:" pl/next-packet-length ", buf: " length? tcp-port/data] either pl/next-packet-length > length? tcp-port/data [; not enough data read tcp-port - ;debug ["keep reading"] + ;sys/log/more 'MySQL["keep reading"] break ][ - ;debug ["current state:" pl/state] + ;sys/log/more 'MySQL["current state:" pl/state] switch/default pl/packet-state [ reading-packet-head [ - ;debug ["read a packet head" mold copy/part tcp-port/data std-header-length] + ;sys/log/more 'MySQL["read a packet head" mold copy/part tcp-port/data std-header-length] parse/all tcp-port/data [ read-int24 (pl/packet-len: int24) read-byte (pl/seq-num: byte) ] pl/packet-state: 'reading-packet pl/next-packet-length: pl/packet-len - ;debug ["expected length of next packet:" pl/next-packet-length] + ;sys/log/more 'MySQL["expected length of next packet:" pl/next-packet-length] remove/part tcp-port/data std-header-length ] reading-packet [ - ;debug ["read a packet"] + ;sys/log/more 'MySQL["read a packet"] either pl/packet-len < 16777215 [; a complete packet is read - debug ["a COMPLETE packet is received"] + sys/log/more 'MySQL["a COMPLETE packet is received"] either pl/data-in-buf? [ append/part pl/buf tcp-port/data pl/packet-len process-a-packet tcp-port pl/buf @@ -1988,7 +1272,7 @@ mysql-driver: make object![ process-a-packet tcp-port tcp-port/data ;adjust `state' for next step ] ][ ; part of a big packet - debug ["a CHUNK of a packet is received"] + sys/log/more 'MySQL["a CHUNK of a packet is received"] pl/data-in-buf?: true append/part pl/buf tcp-port/data pl/packet-len ] @@ -1996,7 +1280,7 @@ mysql-driver: make object![ pl/next-packet-length: std-header-length remove/part tcp-port/data pl/packet-len if pl/stream-end? [ - debug ["stream ended, exiting"] + sys/log/more 'MySQL["stream ended, exiting"] break ] ] @@ -2022,7 +1306,7 @@ mysql-driver: make object![ ][ cause-error 'user 'message ["rows is not properly initialized"] ] - ;debug ["result is properly initialized"] + ;sys/log/more 'MySQL["result is properly initialized"] ] sending-auth-pack [ pl/state: 'reading-auth-resp @@ -2041,13 +1325,13 @@ mysql-driver: make object![ read tcp-port pl/packet-state: 'reading-packet-head pl/next-packet-length: std-header-length - ;;debug "write event" + ;;sys/log/more 'MySQL"write event" ;send more request ;return true ] close [ ;close mysql-port - debug ["TCP port closed"] + sys/log/more 'MySQL["TCP port closed"] close tcp-port emit-event tcp-port 'close return true @@ -2062,14 +1346,14 @@ mysql-driver: make object![ data [string! block!] options [object!] ][ - ;;debug ["inserting to " mold port] - ;debug ["state:" port/locals/state] + ;;sys/log/more 'MySQL["inserting to " mold port] + ;sys/log/more 'MySQL["state:" port/locals/state] either 'idle = port/locals/state [ do-tcp-insert port data options ][ append/only port/locals/o-buf reduce [data options] ] - ;debug [port/spec/scheme "o-buf:" mold port/locals/o-buf] + ;sys/log/more 'MySQL[port/spec/scheme "o-buf:" mold port/locals/o-buf] ] do-tcp-insert: func [ @@ -2080,7 +1364,7 @@ mysql-driver: make object![ /local pl res ][ pl: port/locals - ;debug ["do-tcp-insert" mold data] + ;sys/log/more 'MySQL["do-tcp-insert" mold data] pl/result-options: options pl/query-start-time: now/precise @@ -2139,7 +1423,7 @@ mysql-driver: make object![ opts [object!] /local ret tmp name-fields r ][ - ;debug ["converting results:" mold results] + ;sys/log/more 'MySQL["converting results:" mold results] either any [ port/locals/current-cmd != defs/cmd/query ][;results from multiple queries @@ -2183,19 +1467,17 @@ mysql-driver: make object![ ] ] - system/catalog/errors: make system/catalog/errors [ - MySQL-errors: make object! [;arg1: [error code] ;arg2: error message - code: 1000 - type: "MySQL-errors" - message: ["Error (" :arg1 ")" :arg2] - ] - ]; end system catalog errors -------------- - + + extend system/catalog/errors 'MySQL make object! [ + code: 1000 + type: "MySQL-errors" + message: ["[" :arg1 "]" :arg2] ;arg1: [error code] ;arg2: error message + ] ] sys/make-scheme [ name: 'mysql - title: " Mysql Driver " + title: "MySQL Driver" spec: make system/standard/port-spec-net [ path: % @@ -2211,39 +1493,45 @@ sys/make-scheme [ awake: func [ event [event!] - /local pl cb mode + /local pl cb mode spec ][ - debug ["mysql port event:" event/type] + sys/log/more 'MySQL["mysql port event:" event/type] pl: event/port/locals pl/last-activity: now/precise switch/default event/type [ connect [ - ;debug ["mysql port connected"] + ; remove stored password and rebuild the reference + ; so password is not visible in logs + spec: event/port/spec + spec/pass: none + spec/ref: rejoin [ + mysql:// spec/user #"@" spec/host #":" spec/port-id spec/path + ] + sys/log/info 'MySQL ["Connected:^[[22m" spec/ref] pl/handshaked?: true if pl/exit-wait-after-handshaked? [return true] ] read [ - - ;debug ["pending requests:" mold pl/pending-requests "block size:" pl/pending-block-size] + sys/log/more 'MySQL["pending requests:" mold pl/pending-requests "block size:" pl/pending-block-size] mode: first pl/pending-requests switch/default mode [ async [ cb: second pl/pending-requests case [ function? :cb [ - ;debug ["a function callback:" mold :cb] + ;sys/log/more 'MySQL["a function callback:" mold :cb] cb event/port/data ] any [word? cb path? cb][ - debug ["a word/path callback:" mold cb] + sys/log/more 'MySQL["a word/path callback:" mold cb] set cb event/port/data ] block? cb [ - ;debug ["a block callback:" mold cb] + ;sys/log/more 'MySQL["a block callback:" mold cb] do cb ] none? cb [ - debug ["a none callback, ignored"] + sys/log/more 'MySQL["a none callback, ignored"] ;ignored ] 'else [ @@ -2253,8 +1541,8 @@ sys/make-scheme [ remove/part pl/pending-requests pl/pending-block-size ] sync [ - debug ["got response (" length? event/port/data ")"] - ;debug ["sync mode should exit"] + sys/log/more 'MySQL["got response (" length? event/port/data ")"] + ;sys/log/more 'MySQL["sync mode should exit"] remove/part pl/pending-requests pl/pending-block-size return true ] @@ -2263,10 +1551,10 @@ sys/make-scheme [ ] ] wrote [ - ;debug ["mysql port query sent"] + ;sys/log/more 'MySQL["mysql port query sent"] ] close [ - debug ["port closed"] + sys/log/more 'MySQL["port closed"] cause-error 'Access 'not-connected reduce [event/port none none] ] ][ @@ -2277,24 +1565,24 @@ sys/make-scheme [ actor: [ ; ------------- new open --------- - open: func [ - port[port! url!] - ][ - ;;debug " new open function " - if none? port/spec/host [http-error "Missing host address"] - port/locals: make object! [ - handshaked?: false - exit-wait-after-handshaked?: false - pending-requests: copy [] - pending-block-size: 2 - last-activity: now/precise - async?: false - tcp-port: mysql-driver/open-tcp-port port - ] - - port/awake: :awake - return port + open: func [ + port[port! url!] + ][ + ;;sys/log/more 'MySQL" new open function " + if none? port/spec/host [http-error "Missing host address"] + port/locals: make object! [ + handshaked?: false + exit-wait-after-handshaked?: false + pending-requests: copy [] + pending-block-size: 2 + last-activity: now/precise + async?: false + tcp-port: mysql-driver/open-tcp-port port ] + + port/awake: :awake + return port + ] open?: func [port [port!]][ all [open? port/locals/tcp-port port/locals/handshaked?] @@ -2307,13 +1595,15 @@ sys/make-scheme [ tcp-port: port/locals/tcp-port tcp-port/spec/timeout: 4 if open? tcp-port [ - attempt [;allow this to fail, so the port will always be closed + try [;allow this to fail, so the port will always be closed mysql-driver/send-cmd tcp-port mysql-driver/defs/cmd/quit [] ] ] close tcp-port + sys/log/info 'MySQL ["Closed:^[[22m" port/spec/ref] tcp-port/awake: none port/state: none + port ] insert: func [ @@ -2338,9 +1628,9 @@ sys/make-scheme [ append pl/pending-requests reduce ['sync none] query: data ] - ;debug ["inserting a query:" mold data mold pl/pending-requests] + sys/log/debug 'MySQL["inserting a query:" mold data mold pl/pending-requests] mysql-driver/tcp-insert tcp-port query options - ;;debug ["tcp-port locals after insert" mold tcp-port/locals] + ;sys/log/debug 'MySQL["tcp-port locals after insert" mold tcp-port/locals] ] copy: func [ @@ -2358,6 +1648,7 @@ sys/make-scheme [ ]; end sys/make-scheme send-sql: func [ + port [port!] data [string! block!] /flat "return a flatten block" @@ -2375,61 +1666,51 @@ send-sql: func [ data: reduce [ make mysql-driver/result-option-class [ - flat?: to logic! flat - auto-conv?: not to logic! raw - named?: to logic! named - verbose?: to logic! verbose + flat?: flat + auto-conv?: not raw + named?: named + verbose?: verbose async?: either async [:cb][off] ] data ] insert port data - ;debug ["send-sql: " mold data] - ;debug ["in send-sql, current pending requests:" mold pl/pending-requests] + ;sys/log/more 'MySQL["send-sql: " mold data] + ;sys/log/more 'MySQL["in send-sql, current pending requests:" mold pl/pending-requests] unless async [ - ;debug ["handshaked?:" pl/handshaked?] + ;sys/log/more 'MySQL["handshaked?:" pl/handshaked?] old-handshaked?: pl/handshaked? while [pl/last-activity + port/spec/timeout >= now/precise][ - either port = ret-from-wait: either all [ - system/product = 'atronix-view - any [0 < second system/version 0 < third system/version] - ][ - wait/only [port port/locals/tcp-port port/spec/timeout] ;/only refinement is an atronix enhancement after 3.0.90 - ][ - wait [port port/locals/tcp-port port/spec/timeout] - ][ ;will not return unless: 1) handshaked, 2) sync request processed, or 3) error + ;will not return unless: 1) handshaked, 2) sync request processed, or 3) error + ret-from-wait: wait/only [port port/locals/tcp-port port/spec/timeout] + either port = ret-from-wait [ ;assert [empty? pl/pending-requests] - ;debug ["port/data:" mold port/data] + ;sys/log/more 'MySQL["port/data:" mold port/data] return port/data ][ if port? ret-from-wait [ assert [ret-from-wait = port/locals/tcp-port] print ["******* Unexpected wakeup from tcp-port *********"] ] - ;debug "wait returned none" + ;sys/log/more 'MySQL"wait returned none" cause-error 'Access 'timeout reduce [port none none] ] - ;debug ["trying again..."] + ;sys/log/more 'MySQL["trying again..."] ] cause-error 'Access 'timeout reduce [port none none] ] ] connect-sql: func [ - port [port!] + "Opens connection to MySQL port (waits for a handshake)" + port [port! url!] "MySQL port or url" /local p ][ + if any [url? port not open? port][ port: open port ] port/locals/exit-wait-after-handshaked?: true p: wait/only [port port/locals/tcp-port port/spec/timeout] if port? p [return port] cause-error 'Access 'timeout reduce [port none none] ] -last-mysql-cmd: func [ - port -][ - rejoin ["cmd: " first back find mysql-driver/defs/cmd port/locals/tcp-port/locals/current-cmd - ", data: " mold port/locals/tcp-port/locals/current-cmd-data] -] -; vim: set noexpandtab: