Skip to content

Commit

Permalink
CRM: 3408 - detect and expose SQLite usage (#34868)
Browse files Browse the repository at this point in the history
* Add database engine check

* Add changelog

* CRM: 3406 - address SQLite table creation error (#34872)

* Remove obsolete database table

* Bypass InnoDB check for SQLite

* Add changelog

* CRM: 3404 - address syntax differences between SQLite and MySQL (#34869)

* Update table alias

The `transaction` alias is a reserved keyword in SQLite.

* Implement engine-agnostic build_group_concat()

* Add changelog
  • Loading branch information
tbradsha authored Jan 8, 2024
1 parent 65e9ab0 commit f4c19f2
Show file tree
Hide file tree
Showing 10 changed files with 157 additions and 86 deletions.
6 changes: 1 addition & 5 deletions projects/plugins/crm/admin/system/system-status.page.php
Original file line number Diff line number Diff line change
Expand Up @@ -247,10 +247,6 @@ function zeroBSCRM_render_systemstatus_page() {

global $ZBSCRM_t,$wpdb;
$missingTables = array();
$tablesExist = $wpdb->get_results( "SHOW TABLES LIKE '" . $ZBSCRM_t['keys'] . "'" );
if ( count( $tablesExist ) < 1 ) {
$missingTables[] = $ZBSCRM_t['keys'];
}

// then we cycle through our tables :) - means all keys NEED to be kept up to date :)
foreach ( $ZBSCRM_t as $tableKey => $tableName ) {
Expand Down Expand Up @@ -319,7 +315,7 @@ function zeroBSCRM_render_systemstatus_page() {
'corever' => 'CRM Core Version',
'dbver' => 'Database Version',
'dalver' => 'DAL Version',
'mysql' => 'MySQL Version',
'dbserver' => 'Database Server (version)',
'innodb' => 'InnoDB Storage Engine',
'sqlrights' => 'SQL Permissions',
'locale' => 'Locale',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: fixed

Transactions: Better support for SQLite.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: fixed


Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: added

Database: Added preliminary support for SQLite.
34 changes: 26 additions & 8 deletions projects/plugins/crm/includes/ZeroBSCRM.Core.php
Original file line number Diff line number Diff line change
Expand Up @@ -801,19 +801,37 @@ public function is_database_installed() {
* Retrieves MySQL/MariaDB/Percona database server info
*/
public function get_database_server_info() {

if ( empty( $this->database_server_info ) ) {
global $wpdb;
$raw_version = $wpdb->get_var( 'SELECT VERSION()' );
$version = preg_replace( '/[^0-9.].*/', '', $raw_version );
$is_mariadb = ! ( stripos( $raw_version, 'mariadb' ) === false );

// Adapted from proposed SQLite integration for core
// https://github.com/WordPress/sqlite-database-integration/blob/4a687709bb16a569a7d1ecabfcce433c0e471de8/health-check.php
if ( defined( 'DB_ENGINE' ) && DB_ENGINE === 'sqlite' ) {
$db_engine = DB_ENGINE;
$db_engine_label = 'SQLite';
$raw_version = class_exists( 'SQLite3' ) ? SQLite3::version()['versionString'] : null;
$version = $raw_version;
} else {
global $wpdb;
$raw_version = $wpdb->get_var( 'SELECT VERSION()' ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.DirectQuery
$version = preg_replace( '/[^0-9.].*/', '', $raw_version );
if ( stripos( $raw_version, 'mariadb' ) !== false ) {
$db_engine = 'mariadb';
$db_engine_label = 'MariaDB';
} else {
$db_engine = 'mysql';
$db_engine_label = 'MySQL';
}
}

$database_server_info = array(
'raw_version' => $raw_version,
'version' => $version,
'is_mariadb' => $is_mariadb,
'raw_version' => $raw_version,
'version' => $version,
'db_engine' => $db_engine,
'db_engine_label' => $db_engine_label,
);
$this->database_server_info = $database_server_info;
}

return $this->database_server_info;
}

Expand Down
8 changes: 4 additions & 4 deletions projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Contacts.php
Original file line number Diff line number Diff line change
Expand Up @@ -562,8 +562,8 @@ public function getContact($id=-1,$args=array()){
#} Aliases
if ($withAliases){

#} Retrieve these as a CSV :)
$extraSelect .= ",(SELECT GROUP_CONCAT(aka_alias SEPARATOR ',') FROM ".$ZBSCRM_t['aka']." WHERE aka_type = ".ZBS_TYPE_CONTACT." AND aka_id = contact.ID) aliases";
#} Retrieve these as a CSV :)
$extraSelect .= ',(SELECT ' . $this->DAL()->build_group_concat( 'aka_alias', ',' ) . ' FROM ' . $ZBSCRM_t['aka'] . ' WHERE aka_type = ' . ZBS_TYPE_CONTACT . ' AND aka_id = contact.ID) aliases'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase

}

Expand Down Expand Up @@ -1182,8 +1182,8 @@ public function getContacts($args=array()){
#} Aliases
if ($withAliases){

#} Retrieve these as a CSV :)
$extraSelect .= ",(SELECT GROUP_CONCAT(aka_alias SEPARATOR ',') FROM ".$ZBSCRM_t['aka']." WHERE aka_type = ".ZBS_TYPE_CONTACT." AND aka_id = contact.ID) aliases";
#} Retrieve these as a CSV :)
$extraSelect .= ',(SELECT ' . $this->DAL()->build_group_concat( 'aka_alias', ',' ) . ' FROM ' . $ZBSCRM_t['aka'] . ' WHERE aka_type = ' . ZBS_TYPE_CONTACT . ' AND aka_id = contact.ID) aliases'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase

}

Expand Down
96 changes: 58 additions & 38 deletions projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Transactions.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
* Date: 14/01/19
*/

// phpcs:disable Generic.WhiteSpace.DisallowSpaceIndent.SpacesUsed, WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase

/* ======================================================
Breaking Checks ( stops direct access )
====================================================== */
Expand Down Expand Up @@ -393,7 +395,7 @@ public function getTransaction($id=-1,$args=array()){
if (is_array($custFields)) foreach ($custFields as $cK => $cF){

// add as subquery
$extraSelect .= ',(SELECT zbscf_objval FROM '.$ZBSCRM_t['customfields']." WHERE zbscf_objid = transaction.ID AND zbscf_objkey = %s AND zbscf_objtype = %d LIMIT 1) '".$cK."'";
$extraSelect .= ',(SELECT zbscf_objval FROM ' . $ZBSCRM_t['customfields'] . " WHERE zbscf_objid = transactions.ID AND zbscf_objkey = %s AND zbscf_objtype = %d LIMIT 1) '" . $cK . "'";

// add params
$params[] = $cK; $params[] = ZBS_TYPE_TRANSACTION;
Expand All @@ -402,26 +404,30 @@ public function getTransaction($id=-1,$args=array()){

}

$selector = 'transaction.*';
$selector = 'transactions.*';
if (isset($fields) && is_array($fields)) {
$selector = '';

// always needs id, so add if not present
if (!in_array('ID',$fields)) $selector = 'transaction.ID';
// always needs id, so add if not present
if ( ! in_array( 'ID', $fields, true ) ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable
$selector = 'transactions.ID';
}

foreach ($fields as $f) {
if (!empty($selector)) $selector .= ',';
$selector .= 'transaction.'.$f;
}
} else if ($onlyID){
$selector = 'transaction.ID';
}
foreach ( $fields as $f ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable
if ( ! empty( $selector ) ) {
$selector .= ',';
}
$selector .= 'transactions.' . $f;
}
} elseif ( $onlyID ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable
$selector = 'transactions.ID';
}

#} ============ / PRE-QUERY ===========


#} Build query
$query = "SELECT ".$selector.$extraSelect." FROM ".$ZBSCRM_t['transactions'].' as transaction';
$query = 'SELECT ' . $selector . $extraSelect . ' FROM ' . $ZBSCRM_t['transactions'] . ' AS transactions'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
#} ============= WHERE ================

if (!empty($id) && $id > 0){
Expand Down Expand Up @@ -728,7 +734,7 @@ public function getTransactions($args=array()){
}

// add as subquery
$extraSelect .= ',(SELECT zbscf_objval FROM '.$ZBSCRM_t['customfields']." WHERE zbscf_objid = transaction.ID AND zbscf_objkey = %s AND zbscf_objtype = %d LIMIT 1) ".$cKey;
$extraSelect .= ',(SELECT zbscf_objval FROM ' . $ZBSCRM_t['customfields'] . ' WHERE zbscf_objid = transactions.ID AND zbscf_objkey = %s AND zbscf_objtype = %d LIMIT 1) ' . $cKey;

// add params
$params[] = $cK; $params[] = ZBS_TYPE_TRANSACTION;
Expand All @@ -742,26 +748,28 @@ public function getTransactions($args=array()){
$joinQ .= ' LEFT JOIN (
SELECT
extsrcs.zbss_objid external_source_objid,
GROUP_CONCAT(extsrcs.zbss_uid SEPARATOR "\n") AS external_source_uids,
GROUP_CONCAT(extsrcs.zbss_source SEPARATOR "\n") AS external_source_sources
' . $this->DAL()->build_group_concat( 'extsrcs.zbss_uid', '\n' ) . ' AS external_source_uids,
' . $this->DAL()->build_group_concat( 'extsrcs.zbss_source', '\n' ) . ' AS external_source_sources
FROM
' . $ZBSCRM_t['externalsources'] . ' extsrcs
WHERE
extsrcs.zbss_objtype = %s
GROUP BY extsrcs.zbss_objid
) external_source ON
transaction.ID = external_source.external_source_objid' ;
transactions.ID = external_source.external_source_objid';
$params[] = ZBS_TYPE_TRANSACTION;
}

#} ============ / PRE-QUERY ===========

#} Build query
$query = "SELECT transaction.*".$extraSelect." FROM ".$ZBSCRM_t['transactions'].' as transaction'.$joinQ;
#} Build query
$query = 'SELECT transactions.*' . $extraSelect . ' FROM ' . $ZBSCRM_t['transactions'] . ' AS transactions' . $joinQ;

#} Count override
if ( $count ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable
$query = 'SELECT COUNT(transactions.ID) FROM ' . $ZBSCRM_t['transactions'] . ' AS transactions' . $joinQ;
}

#} Count override
if ($count) $query = "SELECT COUNT(transaction.ID) FROM ".$ZBSCRM_t['transactions'].' as transaction'.$joinQ;

#} onlyColumns override
if ($onlyColumns && is_array($onlyColumnsFieldArr) && count($onlyColumnsFieldArr) > 0){

Expand All @@ -774,14 +782,14 @@ public function getTransactions($args=array()){

}

$query = "SELECT ".$columnStr." FROM ".$ZBSCRM_t['transactions'].' as transaction'.$joinQ;
$query = 'SELECT ' . $columnStr . ' FROM ' . $ZBSCRM_t['transactions'] . ' AS transactions' . $joinQ;

}

// $total only override
if ( $total ){
$query = "SELECT SUM(transaction.zbst_total) total FROM ".$ZBSCRM_t['transactions'].' as transaction'.$joinQ;

$query = 'SELECT SUM(transactions.zbst_total) total FROM ' . $ZBSCRM_t['transactions'] . ' AS transactions' . $joinQ;

}

Expand Down Expand Up @@ -924,9 +932,12 @@ public function getTransactions($args=array()){

if (!is_array($isTagged) && !empty($isTagged) && $isTagged > 0){

// add where tagged
// 1 int:
$wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = transaction.ID AND zbstl_tagid = %d) > 0)',array(ZBS_TYPE_TRANSACTION,$isTagged));
// add where tagged
// 1 int:
$wheres['direct'][] = array(
'((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = transactions.ID AND zbstl_tagid = %d) > 0)',
array( ZBS_TYPE_TRANSACTION, $isTagged ),
);

} else if (is_array($isTagged) && count($isTagged) > 0){

Expand All @@ -941,8 +952,11 @@ public function getTransactions($args=array()){
}
}
if (!empty($tagStr)){

$wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = transaction.ID AND zbstl_tagid IN (%s)) > 0)',array(ZBS_TYPE_TRANSACTION,$tagStr));

$wheres['direct'][] = array(
'((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = transactions.ID AND zbstl_tagid IN (%s)) > 0)',
array( ZBS_TYPE_TRANSACTION, $tagStr ),
);

}

Expand All @@ -954,9 +968,12 @@ public function getTransactions($args=array()){

if (!is_array($isNotTagged) && !empty($isNotTagged) && $isNotTagged > 0){

// add where tagged
// 1 int:
$wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = transaction.ID AND zbstl_tagid = %d) = 0)',array(ZBS_TYPE_TRANSACTION,$isNotTagged));
// add where tagged
// 1 int:
$wheres['direct'][] = array(
'((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = transactions.ID AND zbstl_tagid = %d) = 0)',
array( ZBS_TYPE_TRANSACTION, $isNotTagged ),
);

} else if (is_array($isNotTagged) && count($isNotTagged) > 0){

Expand All @@ -971,8 +988,11 @@ public function getTransactions($args=array()){
}
}
if (!empty($tagStr)){

$wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = transaction.ID AND zbstl_tagid IN (%s)) = 0)',array(ZBS_TYPE_TRANSACTION,$tagStr));

$wheres['direct'][] = array(
'((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = transactions.ID AND zbstl_tagid IN (%s)) = 0)',
array( ZBS_TYPE_TRANSACTION, $tagStr ),
);

}

Expand All @@ -990,12 +1010,12 @@ public function getTransactions($args=array()){

// Mapped sorts
// This catches listview and other exception sort cases
$sort_map = array(
$sort_map = array(

// Note: "customer" here could be company or contact, so it's not a true sort (as no great way of doing this beyond some sort of prefix comparing)
'customer' => '(SELECT ID FROM '.$ZBSCRM_t['contacts'].' WHERE ID IN (SELECT zbsol_objid_to FROM '.$ZBSCRM_t['objlinks'].' WHERE zbsol_objtype_from = '.ZBS_TYPE_TRANSACTION.' AND zbsol_objtype_to = '.ZBS_TYPE_CONTACT.' AND zbsol_objid_from = transaction.ID))',
// Note: "customer" here could be company or contact, so it's not a true sort (as no great way of doing this beyond some sort of prefix comparing)
'customer' => '(SELECT ID FROM ' . $ZBSCRM_t['contacts'] . ' WHERE ID IN (SELECT zbsol_objid_to FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_TRANSACTION . ' AND zbsol_objtype_to = ' . ZBS_TYPE_CONTACT . ' AND zbsol_objid_from = transactions.ID))',

);
);

if ( array_key_exists( $sortByField, $sort_map ) ) {

Expand Down
17 changes: 17 additions & 0 deletions projects/plugins/crm/includes/ZeroBSCRM.DAL3.php
Original file line number Diff line number Diff line change
Expand Up @@ -7405,6 +7405,23 @@ public function buildWPMetaQueryWhere($metaKey=-1,$metaVal=-1){

}

/**
* Generates GROUP_CONCAT SQL compatible with both SQLite and MySQL
*
* @param string $field Field that will be concatenated.
* @param string $separator Separator added between concatenated fields.
*
* @return string
*/
public function build_group_concat( $field, $separator ) {
$db_engine = jpcrm_database_engine();
if ( $db_engine === 'sqlite' ) {
return sprintf( 'GROUP_CONCAT(%s, "%s")', $field, $separator );
} else {
return sprintf( 'GROUP_CONCAT(%s SEPARATOR "%s")', $field, $separator );
}
}

// this returns %s etc. for common field names, will default to %s unless somt obv a date
public function getTypeStr($fieldKey=''){

Expand Down
Loading

0 comments on commit f4c19f2

Please sign in to comment.