enum _:__QS_ARRAY { SQL_QUERY_MODE:__SQL_MODE, __TABLE[__SQL_TABLE_SIZE_BUFF], Array:__COLUMN, Array:__DATA, Array:__WHERE_C, Array:__WHERE_D, __WHERE_MANUAL[__SQL_MAX_COLUMN_BUF_SIZE] } /** * Inicia Preparacion de la oracion sql * * @param mode Modo * * @return identificador del inicios * */ stock SQL_DATA:sql_init(SQL_QUERY_MODE:mode) { if(!(SQL_INSERT <= mode <= SQL_UPDATE)) { log_error(AMX_ERR_NATIVE, "[AMXX] SQL Mode not valid!") return any:0; } new a[__QS_ARRAY], num[__SQL_MAX_IDENTIFIER_NUMS]; if(!_QUERY_SENTENCER) { _QUERY_SENTENCER = TrieCreate() } a[__SQL_MODE] = mode _QUERY_IDENTIFIER += 1; num_to_str(_QUERY_IDENTIFIER, num, charsmax(num)) TrieSetArray(_QUERY_SENTENCER, num, a, sizeof(a)) return _QUERY_IDENTIFIER; } /** * Establece la tabla a trabajar * * @param id Identificador * @param table Tabla a trabajar * * @noreturn * */ stock sql_set_table(SQL_DATA:id, const table[]) { new a[__QS_ARRAY], num[__SQL_MAX_IDENTIFIER_NUMS]; num_to_str(any:id, num, charsmax(num)) if(TrieGetArray(_QUERY_SENTENCER, num, a, sizeof(a)) == false) { log_error(AMX_ERR_NATIVE, "[AMXX] SQL DATA ID not valid!") return; } formatex(a[__TABLE], charsmax(a[__TABLE]), "%s", table); TrieSetArray(_QUERY_SENTENCER, num, a, sizeof(a)) } /** * Establece la tabla a trabajar * * @param id Identificador * @param column Establece una columna * @param data Datos a establecer en una columna * @param ... Datos para formatear el texto establecido en data * * @noreturn * */ stock sql_set_value(SQL_DATA:id, const column[], const data[], any:...) { new a[__QS_ARRAY], num[__SQL_MAX_IDENTIFIER_NUMS], buff[__SQL_MAX_COLUMN_BUF_SIZE]; num_to_str(any:id, num, charsmax(num)) if(TrieGetArray(_QUERY_SENTENCER, num, a, sizeof(a)) == false) { log_error(AMX_ERR_NATIVE, "[AMXX] SQL DATA ID not valid!") return; } vformat(buff, charsmax(buff), data, 4); new Array:c = a[__COLUMN]; new Array:d = a[__DATA]; if(!c) { c = ArrayCreate(__SQL_MAX_COLUMN_BUF_SIZE) d = ArrayCreate(__SQL_MAX_COLUMN_BUF_SIZE) a[__COLUMN] = c a[__DATA] = d } replace_all(buff, charsmax(buff), "\", "\\"); replace_all(buff, charsmax(buff), "^"", "\^"");
ArrayPushString(c, column) ArrayPushString(d, buff) TrieSetArray(_QUERY_SENTENCER, num, a, sizeof(a)) } /** * Actualiza datos de una columna * Esta funcion esta pensada para usar numeros enteros/flotantes * Pero se pueden usar strings * * @param id Identificador * @param column Establece una columna * @param data Datos a establecer en una columna * @param update_with_other_column con true para actualizar con datos de otra columna * @param update_from si "update_with_other_column" se estable en true se debe establecer la columna para tomar los datos de esa columna * @param update_operator se utiliza un operador logico para relizar operaciones matematicas usando de base los datos de la columna establecida por "update_from" * * @noreturn * */ stock sql_update_value(SQL_DATA:id, const column[], const data[], bool:update_with_other_column=false, const update_from[]="", const update_operator[]="") { new a[__QS_ARRAY], num[__SQL_MAX_IDENTIFIER_NUMS], buff[__SQL_MAX_COLUMN_BUF_SIZE]; num_to_str(any:id, num, charsmax(num)) if(TrieGetArray(_QUERY_SENTENCER, num, a, sizeof(a)) == false) { log_error(AMX_ERR_NATIVE, "[AMXX] SQL DATA ID not valid!") return; } if(a[__SQL_MODE] != SQL_UPDATE) { log_error(AMX_ERR_NATIVE, "[AMXX] SQL DATA ID IS NOT UPDATE MODE!") return; } new Array:c = a[__COLUMN]; new Array:d = a[__DATA]; if(!c) { c = ArrayCreate(__SQL_MAX_COLUMN_BUF_SIZE) d = ArrayCreate(__SQL_MAX_COLUMN_BUF_SIZE) a[__COLUMN] = c a[__DATA] = d } if(update_with_other_column && update_from[0] && update_operator[0]) { formatex(buff, charsmax(buff), "`%s`%s%i", update_from, update_operator, str_to_num(data)); } else { copy(buff, charsmax(buff), data) replace_all(buff, charsmax(buff), "\", "\\"); replace_all(buff, charsmax(buff), "^"", "\^"");
} ArrayPushString(c, column) ArrayPushString(d, buff) TrieSetArray(_QUERY_SENTENCER, num, a, sizeof(a)) } /** * Establece una condicion manual * * @param id Identificador * @param where Establece una condicion de manera manual * @param ... Datos para formatear el texto establecido en where * * @noreturn * */ stock sql_set_where_manual(SQL_DATA:id, const where[], any:...) { new a[__QS_ARRAY], num[__SQL_MAX_IDENTIFIER_NUMS] num_to_str(any:id, num, charsmax(num)) if(TrieGetArray(_QUERY_SENTENCER, num, a, sizeof(a)) == false) { log_error(AMX_ERR_NATIVE, "[AMXX] SQL DATA ID not valid!") return; } vformat(a[__WHERE_MANUAL], charsmax(a[__WHERE_MANUAL]), where, 3); TrieSetArray(_QUERY_SENTENCER, num, a, sizeof(a)) } /** * Establece una condicion Formateada * * @param id Identificador * @param ... Se establece una condicion sql preformateada con datos, * donde el primer argumento sera la columna y el segundo * argumento seria el dato de la columna a verificar * Este argumento tendra un "escape string", los * argumentos siguentes argumetos se cumpliran de la misma * manera que el argumento 1 y 2 * * @note Ejemplo: sql_set_where(id, "user", "SU^"GI") * en la oracion sql se rellenaria asi WHERE `user`="SU\"GI" * Otro Ejemplo sql_set_where(id, "user", "SU^"GI", "password", "Sugiiiiisaiiii^"^"") * en la oracion sql se rellenaria asi WHERE `user`="SU\"GI" AND `password`="Sugiiiiisaiiii\"\"" * * * @noreturn * */ stock sql_set_where(SQL_DATA:id, any:...) { new a[__QS_ARRAY], num[__SQL_MAX_IDENTIFIER_NUMS], data[__SQL_MAX_COLUMN_BUF_SIZE] num_to_str(any:id, num, charsmax(num)) if(TrieGetArray(_QUERY_SENTENCER, num, a, sizeof(a)) == false) { log_error(AMX_ERR_NATIVE, "[AMXX] SQL DATA ID not valid!") return; } new Array:c = a[__WHERE_C]; new Array:d = a[__WHERE_D]; if(!c) { c = ArrayCreate(__SQL_MAX_COLUMN_BUF_SIZE) d = ArrayCreate(__SQL_MAX_COLUMN_BUF_SIZE) a[__WHERE_C] = c a[__WHERE_D] = d } new pos, ch; for(new i = 1 ; i < numargs() ; i++) { pos = 0; while((ch = getarg(i, pos ))) { data[pos++] = ch; } data[pos++] = '^0'; if((i % 2) == 0) { replace_all(data, charsmax(data), "\", "\\"); replace_all(data, charsmax(data), "^"", "\^""); ArrayPushString(d, data); } else { ArrayPushString(c, data); } } TrieSetArray(_QUERY_SENTENCER, num, a, sizeof(a)) } /** * Ejecuta una una Oracion SQL * * @note The handler should look like: * public QueryHandler(failstate, Handle:query, error[], errnum, data[], size, Float:queuetime) * failstate - One of the three TQUERY_ defines. * query - Handle to the query, do not free it. * error - An error message, if any. * errnum - An error code, if any. * data - Data array you passed in. * size - Size of the data array you passed in. * queuetime - Amount of gametime that passed while the query was resolving. * @note This will not interrupt gameplay in the event of a poor/lossed * connection, however, the interface is more complicated and * asynchronous. Furthermore, a new connection/disconnection is * made for each query to simplify driver support. * @note The handle does not need to be freed. * * @param id Identificador * @param SQL_TUPLE Tuple handle, returned from SQL_MakeDbTuple(). * @param Handler A function to be called when the query finishes. It has to be public. * @param data Additional data array that will be passed to the handler function. * @param dataSize The size of the additional data array. * * * @noreturn * */ stock sql_execute(SQL_DATA:id, Handle:SQL_TUPLE, const Handler[], const szData[]="", DataSize=0) { new a[__QS_ARRAY], num[__SQL_MAX_IDENTIFIER_NUMS], data[__SQL_MAX_COLUMN_BUF_SIZE], query[__SQL_MAX_QUERY_BUF_SIZE], len; num_to_str(any:id, num, charsmax(num)) if(TrieGetArray(_QUERY_SENTENCER, num, a, sizeof(a)) == false) { log_error(AMX_ERR_NATIVE, "[AMXX] SQL DATA ID not valid!") return; }
len = formatex(query, charsmax(query), "%s `%s` ", a[__SQL_MODE] == SQL_INSERT ? "INSERT INTO" : a[__SQL_MODE] == SQL_UPDATE ? "UPDATE" : "", a[__TABLE]) new Array:d, Array:c, i; c = a[__COLUMN]; d = a[__DATA]; if(a[__SQL_MODE] == SQL_INSERT) { len += add(query[len], charsmax(query), "("); for( i = 0 ; i < ArraySize(c) ; i++) { ArrayGetString(c, i, data, charsmax(data)) len += formatex(query[len], charsmax(query), "%s`%s`", i > 0 ? "," : "", data); } len += add(query[len], charsmax(query), ") VALUES ("); for( i = 0 ; i < ArraySize(d) ; i++) { ArrayGetString(d, i, data, charsmax(data)) len += formatex(query[len], charsmax(query), "%s^"%s^"", i > 0 ? "," : "", data); } len += add(query[len], charsmax(query), ")"); } else if(a[__SQL_MODE] == SQL_UPDATE) { len += add(query[len], charsmax(query), "SET "); new data2[__SQL_MAX_COLUMN_BUF_SIZE] for( i = 0 ; i < ArraySize(c) ; i++) { ArrayGetString(c, i, data, charsmax(data)) ArrayGetString(d, i, data2, charsmax(data2)) len += formatex(query[len], charsmax(query), "%s`%s`=%s%s%s", i > 0 ? "," : "", data, data2[0] != '`' ? "^"" : "", data2, data2[0] != '`' ? "^"" : ""); } if(!a[__WHERE_MANUAL]) { new Array:wc, Array:wd; wd = a[__WHERE_D] wc = a[__WHERE_C] len += add(query[len], charsmax(query), " WHERE "); for(new i = 0 ; i < ArraySize(wc) ; i++) { ArrayGetString(wc, i, data, charsmax(data)) ArrayGetString(wd, i, data2, charsmax(data2)) len += formatex(query[len], charsmax(query), "%s`%s`=^"%s^"", i > 0 ? " AND " : "", data, data2) } ArrayDestroy(wc) ArrayDestroy(wd) } else { len += formatex(query[len], charsmax(query), " WHERE %s", a[__WHERE_MANUAL]); }
Excelente aporte @Sugisaki, estaría bueno también que añadas:
Código PHP:
sql_set_where(where[]="", any:...) // En el caso que sea algun SELECT? sql_set_order(order[]="") // En el caso que sea algun SELECT? sql_set_limit(start, end) // En el caso que sea algun SELECT?
Eficiente sería que hacer una consulta tome una sola línea de código sino por qué alguien se molestaría escribiendo 5 líneas para hacer un simple update?
Podés comprobar en el sma de mi plugin de estadísticas generales donde armé una función (muy pobre pero sirve como concepto) para realizar muchas consultas pero había quedado breve y simple.
Además, nombrás a tus funciones como "prepare" pero no son técnicamente consultas preparadas así que tenés que utilizar la función escape en cada valor para evitar SQL injection, de otra forma, nosotros al usar tu código tenemos que usar escape lo cual sería ultra tedioso y extenso, aparte todos se olvidan de hacerlo.
No inspira confianza usar un código donde hay una función llamada "STUPID_FUNCTION".
Podés cambiarlo a "sql_init" y que nosotros tengamos que añadirlo en plugin_init así evitás llamadas innecesarias pero lo importante era el nombre de la función.
Podrías intentar organizar el código en un .inc así como hice en mis redes neuronales o sino también podés crear natives, aunque es más simple include.
(01/12/2019, 04:30 PM)totopizza escribió: Excelente aporte @Sugisaki, estaría bueno también que añadas:
Código PHP:
sql_set_where(where[]="", any:...) // En el caso que sea algun SELECT? sql_set_order(order[]="") // En el caso que sea algun SELECT? sql_set_limit(start, end) // En el caso que sea algun SELECT?
No te olvides del identificador.
Código PHP:
new SQL_DATA:sid = sql_prepare_update("pug_stats_player", "id='%i' ORDER BY id DESC LIMIT 1", 1); // sql_set_value ... // sql_execute ...
(02/12/2019, 02:37 PM)LuKks escribió: Eficiente sería que hacer una consulta tome una sola línea de código sino por qué alguien se molestaría escribiendo 5 líneas para hacer un simple update?
A que te refieres cuando dices eficiencia?
Tecnicamente no estas enviando consultas por el numero de funciones sql_* que exista en un frame.
"Eficiente" seria realizar una consulta update extremadamente larga de una manera la cual sea legible.
Imagina tener mmmmm 15 columnas, las cual, las acualizas/insertas cada vez que se desconecta un jugador, tendrias que realizar tecnicas en el editor para poder formatear la "Oracion SQL" la cual no se te mezcle datos de una columna con otra, o que te falte una variable, o que agreges columnas nuevas al proyecto. La tecnica que usaba era alinear las columnas con los caracteres de escape y las variables unas abajo de otras para no tener problemas de formato ya que se retrasaria el proyecto
(02/12/2019, 02:37 PM)LuKks escribió: Además, nombrás a tus funciones como "prepare" pero no son técnicamente consultas preparadas así que tenés que utilizar la función escape en cada valor para evitar SQL injection, de otra forma, nosotros al usar tu código tenemos que usar escape lo cual sería ultra tedioso y extenso, aparte todos se olvidan de hacerlo.
no esta diseñado para captar datos introducidos por el usuario, si te refieres al nombre, basta con hacer
Código PHP:
sql_set_value(x, "x", "^"%s^"", name
(02/12/2019, 02:37 PM)LuKks escribió: No inspira confianza usar un código donde hay una función llamada "STUPID_FUNCTION".
Podés cambiarlo a "sql_init" y que nosotros tengamos que añadirlo en plugin_init así evitás llamadas innecesarias pero lo importante era el nombre de la función.
no hace peso esa condicion, se puede mejorar, pero lo hice por lo mas rapido
estare por mejorar esas cositas
(02/12/2019, 04:42 PM)Sugisaki escribió: A que te refieres cuando dices eficiencia?
Tecnicamente no estas enviando consultas por el numero de funciones sql_* que exista en un frame.
"Eficiente" seria realizar una consulta update extremadamente larga de una manera la cual sea legible.
Mala elección mía de palabra, quise decir más productivo en cuanto a escribir el código necesario para realizar la consulta.
(02/12/2019, 04:42 PM)Sugisaki escribió: no esta diseñado para captar datos introducidos por el usuario, si te refieres al nombre, basta con hacer
Código PHP:
sql_set_value(x, "x", "^"%s^"", name
Eso no evita SQL injection. Lo que sucede es que ^" sirve para insertar comilla sin hacer conflicto de sintaxis en AMXX.
En MySQL los strings van entre comillas y en AMXX los strings también se definen con comillas.
Lo mismo para el resto de valores, tablas, queries, etcétera.
Algunas const con valores máximos podría resolverlo, si alguien necesita más sería fácil de incrementar.
__count no provoca un error cuando se pase el límite máximo de integer? Si count vuelve a cero el código seguiría funcionando correctamente?
(02/12/2019, 06:15 PM)LuKks escribió: Eso no evita SQL injection. Lo que sucede es que ^" sirve para insertar comilla sin hacer conflicto de sintaxis en AMXX.
En MySQL los strings van entre comillas y en AMXX los strings también se definen con comillas.
(30/10/2014, 04:30 PM)meTaLiCroSS escribió: El string seria tomado como "holamundo'peperulz'jeje'", solo tomara como inicio y termino las comillas dobles, las comillas simples no importaran un huevo. Y un nombre de CS no puede tener comilla doble, entonces no hay de que atarearse.
(02/12/2019, 06:15 PM)LuKks escribió: Aprovecho para decir que las llaves quedan mejor así:
Código PHP:
if(i == 0) { len += formatex(query[len], charsmax(query), "`%s`", data); } else { len += formatex(query[len], charsmax(query), ",`%s`", data); }
eso depende del programador no afecta la logica del codigo
(02/12/2019, 06:15 PM)LuKks escribió: Lo importante es que si vemos código repetido, casi siempre hay una forma de reducirlo:
Código PHP:
len += formatex(query[len], charsmax(query), "%s`%s`", i == 0 ? "" : ",", data);
, si eso lo vi, si ves un poco mas baja esta esa condicion y me dio pereza modificarla
(02/12/2019, 06:15 PM)LuKks escribió: Si paso un string de 300 caracteres no alcanza el buffer:
que columna tendra mas de 256 caracteres?
(02/12/2019, 06:15 PM)LuKks escribió: __count no provoca un error cuando se pase el límite máximo de integer? Si count vuelve a cero el código seguiría funcionando correctamente?
no hay problema, al momento que se ejecuta sql_execute se elimina los datos referente a la identificacion dejandola libre
PD: tiene que ser uns sv que nunca se apague para que llegue a su valor maximo (2,147,483,647)
(02/12/2019, 06:15 PM)LuKks escribió: Eso no evita SQL injection. Lo que sucede es que ^" sirve para insertar comilla sin hacer conflicto de sintaxis en AMXX.
En MySQL los strings van entre comillas y en AMXX los strings también se definen con comillas.
(30/10/2014, 04:30 PM)meTaLiCroSS escribió: El string seria tomado como "holamundo'peperulz'jeje'", solo tomara como inicio y termino las comillas dobles, las comillas simples no importaran un huevo. Y un nombre de CS no puede tener comilla doble, entonces no hay de que atarearse.
Entonces habría que eliminar la función escape porque no sirve para nada, quién fue el tonto que la creó?
Quitando el sarcasmo, no estamos hablando del valor name únicamente, estamos hablando de cualquier valor de tipo string.
Por ejemplo, mi contraseña es hw"y1!23
Código PHP:
new password[] = "hw^"y1!23"; sql_prepare_update("pug_stats_player", "password = ^"%s^"", password);
La query va a quedar: password = "hw"y1!23"
Por lo tanto va a fallar, y gracias al universo no fue SQL injection.
(02/12/2019, 07:47 PM)Sugisaki escribió:
(02/12/2019, 06:15 PM)LuKks escribió: Aprovecho para decir que las llaves quedan mejor así:
Código PHP:
if(i == 0) { len += formatex(query[len], charsmax(query), "`%s`", data); } else { len += formatex(query[len], charsmax(query), ",`%s`", data); }
eso depende del programador no afecta la logica del codigo
Eso depende de si querés que otro desarrollador lea tu código.
Publicamos aportes porque queremos que otros lo vean, lean, usen, etcétera.
Es como escribir un libro con faltas ortográficas, seguro que las palabras se entienden pero se sufre mucho al leer y menos personas lo terminan leyendo.
(02/12/2019, 07:47 PM)Sugisaki escribió:
(02/12/2019, 06:15 PM)LuKks escribió: Lo importante es que si vemos código repetido, casi siempre hay una forma de reducirlo:
Código PHP:
len += formatex(query[len], charsmax(query), "%s`%s`", i == 0 ? "" : ",", data);
, si eso lo vi, si ves un poco mas baja esta esa condicion y me dio pereza modificarla
(02/12/2019, 06:15 PM)LuKks escribió: Si paso un string de 300 caracteres no alcanza el buffer:
que columna tendra mas de 256 caracteres?
Es obvio que probablemente ninguna columna pero valores? E incluso múltiples valores?
Por ejemplo, estoy registrando todo lo que los usuarios dicen por say y alguien escribe 250 caracteres, entonces ya no me alcanza porque todavía falta INSERT y demás partes de la query.
Y si en la misma query estoy registrando el nombre, la fecha y otros datos? No alcanza.
Leyendo noté que el buffer de count es de 4:
Código PHP:
new num[4]
Cuando count llegue a 10000 entonces num va a quedar 1000.
Y si continúo haciendo consultas num va a seguir siendo 1000 nueve veces más, lo cual provocaría resultados inesperados (query no enviada o error dependiendo del código).
(02/12/2019, 07:47 PM)Sugisaki escribió:
(02/12/2019, 06:15 PM)LuKks escribió: __count no provoca un error cuando se pase el límite máximo de integer? Si count vuelve a cero el código seguiría funcionando correctamente?
no hay problema, al momento que se ejecuta sql_execute se elimina los datos referente a la identificacion dejandola libre
Me refería a count mismo, pero poco importa ya que ahora está el problema del buffer num.
Mis comentarios son simplemente feedback para que mejores aún más el aporte, no tenés que aplicar nada de lo que dije pero no te molesta la posibilidad de que tu código le genere errores o problemas en los plugins de otras personas?
(02/12/2019, 09:45 PM)LuKks escribió: Es obvio que probablemente ninguna columna pero valores? E incluso múltiples valores?
Por ejemplo, estoy registrando todo lo que los usuarios dicen por say y alguien escribe 250 caracteres, entonces ya no me alcanza porque todavía falta INSERT y demás partes de la query.
Y si en la misma query estoy registrando el nombre, la fecha y otros datos? No alcanza.
el tamaño maximo final de la oracion es 1280 lo de 256 es el tamaño buffer por columna
Código PHP:
stock sql_execute(SQL_DATA:sql_id, Handle:hquery, const handler[], const szData[]="", datasize=0) { new query[1280], data[256], i, len, num[4], m; }
(02/12/2019, 09:45 PM)LuKks escribió: Eso depende de si querés que otro desarrollador lea tu código.
Publicamos aportes porque queremos que otros lo vean, lean, usen, etcétera.
Es como escribir un libro con faltas ortográficas, seguro que las palabras se entienden pero se sufre mucho al leer y menos personas lo terminan leyendo.
ve arkshine's indent
recalco siempre y cuando no afecte la funcionalidad lo puedes escribir como sea, eso es comodidad del programador, a mi no me gustan las cosas amontonadas, queda feo a simple vista
(RegameDLL Github)
(02/12/2019, 09:45 PM)LuKks escribió: Cuando count llegue a 10000 entonces num va a quedar 1000.
Y si continúo haciendo consultas num va a seguir siendo 1000 nueve veces más, lo cual provocaría resultados inesperados (query no enviada o error dependiendo del código).
mmm no tanto, ya que al llamar sql_execute en el mismo frame del sql_prepare* se eliminara su contenido peeero si pospones la ejecucion del sql_execute para se llame en otro frame o estes usando 2 o mas sql_prepare* en paralelo ahi si te puedes asustar, pero hay que ser medio maniatico para hacer 999+ en menos de 30 min (tiempo promedio de duracion del mapa)
(02/12/2019, 09:45 PM)LuKks escribió: Mis comentarios son simplemente feedback para que mejores aún más el aporte
Sep lo entiendo y lo agradezco , no me molesto, solo respondo tus inquietudes
(02/12/2019, 09:45 PM)LuKks escribió: no tenés que aplicar nada de lo que dije pero no te molesta la posibilidad de que tu código le genere errores o problemas en los plugins de otras personas?
de errores se aprende , yo tengo una manera peculiar de hacer un proyecto primero hago algo lo cual es lo mas feo posible ya que se me da por la mente asi, sobre la marcha voy aplicando parches y mejoras sobre el mismo, cambiando funciones y hasta rework el proyecto entero puedes echarle un ojo al fpug, ve la version 1.21 que esta en am-es y ve la de github, veras que funcionan IGUAL, pero escrito de otra manera
// public update(table[], any:...) {} public insert(table[], any:...) {}
Esto de simplificar las queries lo hice en PHP hace años (http://i.imgur.com/YAQeeKl.png).
Hace bastante lo re-hice en Node.js que es donde te dije que obtengas ideas: like-mysql
Pensá que ya todos lograron hacer sus plugins con mysql sin tu librería entonces por qué deberían usarla? Por eso tiene que ser suficientemente buena así vale la pena depender de la librería.
Destro no te publica el vault medio armado con funciones básicas faltantes, te publica todo el sistema completo de manera consistente y con actualizaciones retrocompatibles.
Sí, sin comillas.
Vos como librería ya tenés el %s que indica que es un string así que se pueden añadir automáticamente y les ahorrás a todos tanto drama con comillas.