@@ -356,7 +356,7 @@ public function ignore(bool $ignore = true)
356356 /**
357357 * Generates the SELECT portion of the query
358358 *
359- * @param array|string $select
359+ * @param array|RawSql| string $select
360360 *
361361 * @return $this
362362 */
@@ -371,6 +371,12 @@ public function select($select = '*', ?bool $escape = null)
371371 $ escape = $ this ->db ->protectIdentifiers ;
372372 }
373373
374+ if ($ select instanceof RawSql) {
375+ $ this ->QBSelect [] = $ select ;
376+
377+ return $ this ;
378+ }
379+
374380 foreach ($ select as $ val ) {
375381 $ val = trim ($ val );
376382
@@ -643,8 +649,8 @@ public function join(string $table, string $cond, string $type = '', ?bool $esca
643649 * Generates the WHERE portion of the query.
644650 * Separates multiple calls with 'AND'.
645651 *
646- * @param mixed $key
647- * @param mixed $value
652+ * @param array|RawSql|string $key
653+ * @param mixed $value
648654 *
649655 * @return $this
650656 */
@@ -659,9 +665,9 @@ public function where($key, $value = null, ?bool $escape = null)
659665 * Generates the WHERE portion of the query.
660666 * Separates multiple calls with 'OR'.
661667 *
662- * @param mixed $key
663- * @param mixed $value
664- * @param bool $escape
668+ * @param array|RawSql|string $key
669+ * @param mixed $value
670+ * @param bool $escape
665671 *
666672 * @return $this
667673 */
@@ -676,26 +682,34 @@ public function orWhere($key, $value = null, ?bool $escape = null)
676682 * @used-by having()
677683 * @used-by orHaving()
678684 *
679- * @param mixed $key
680- * @param mixed $value
685+ * @param array|RawSql|string $key
686+ * @param mixed $value
681687 *
682688 * @return $this
683689 */
684690 protected function whereHaving (string $ qbKey , $ key , $ value = null , string $ type = 'AND ' , ?bool $ escape = null )
685691 {
686- if (! is_array ($ key )) {
687- $ key = [$ key => $ value ];
692+ if ($ key instanceof RawSql) {
693+ $ keyValue = [(string ) $ key => $ key ];
694+ $ escape = false ;
695+ } elseif (! is_array ($ key )) {
696+ $ keyValue = [$ key => $ value ];
697+ } else {
698+ $ keyValue = $ key ;
688699 }
689700
690701 // If the escape value was not set will base it on the global setting
691702 if (! is_bool ($ escape )) {
692703 $ escape = $ this ->db ->protectIdentifiers ;
693704 }
694705
695- foreach ($ key as $ k => $ v ) {
706+ foreach ($ keyValue as $ k => $ v ) {
696707 $ prefix = empty ($ this ->{$ qbKey }) ? $ this ->groupGetType ('' ) : $ this ->groupGetType ($ type );
697708
698- if ($ v !== null ) {
709+ if ($ v instanceof RawSql) {
710+ $ k = '' ;
711+ $ op = '' ;
712+ } elseif ($ v !== null ) {
699713 $ op = $ this ->getOperator ($ k , true );
700714
701715 if (! empty ($ op )) {
@@ -731,10 +745,17 @@ protected function whereHaving(string $qbKey, $key, $value = null, string $type
731745 $ op = '' ;
732746 }
733747
734- $ this ->{$ qbKey }[] = [
735- 'condition ' => $ prefix . $ k . $ op . $ v ,
736- 'escape ' => $ escape ,
737- ];
748+ if ($ v instanceof RawSql) {
749+ $ this ->{$ qbKey }[] = [
750+ 'condition ' => $ v ->with ($ prefix . $ k . $ op . $ v ),
751+ 'escape ' => $ escape ,
752+ ];
753+ } else {
754+ $ this ->{$ qbKey }[] = [
755+ 'condition ' => $ prefix . $ k . $ op . $ v ,
756+ 'escape ' => $ escape ,
757+ ];
758+ }
738759 }
739760
740761 return $ this ;
@@ -911,7 +932,7 @@ protected function _whereIn(?string $key = null, $values = null, bool $not = fal
911932 * Generates a %LIKE% portion of the query.
912933 * Separates multiple calls with 'AND'.
913934 *
914- * @param mixed $field
935+ * @param array|RawSql|string $field
915936 *
916937 * @return $this
917938 */
@@ -924,7 +945,7 @@ public function like($field, string $match = '', string $side = 'both', ?bool $e
924945 * Generates a NOT LIKE portion of the query.
925946 * Separates multiple calls with 'AND'.
926947 *
927- * @param mixed $field
948+ * @param array|RawSql|string $field
928949 *
929950 * @return $this
930951 */
@@ -937,7 +958,7 @@ public function notLike($field, string $match = '', string $side = 'both', ?bool
937958 * Generates a %LIKE% portion of the query.
938959 * Separates multiple calls with 'OR'.
939960 *
940- * @param mixed $field
961+ * @param array|RawSql|string $field
941962 *
942963 * @return $this
943964 */
@@ -950,7 +971,7 @@ public function orLike($field, string $match = '', string $side = 'both', ?bool
950971 * Generates a NOT LIKE portion of the query.
951972 * Separates multiple calls with 'OR'.
952973 *
953- * @param mixed $field
974+ * @param array|RawSql|string $field
954975 *
955976 * @return $this
956977 */
@@ -963,7 +984,7 @@ public function orNotLike($field, string $match = '', string $side = 'both', ?bo
963984 * Generates a %LIKE% portion of the query.
964985 * Separates multiple calls with 'AND'.
965986 *
966- * @param mixed $field
987+ * @param array|RawSql|string $field
967988 *
968989 * @return $this
969990 */
@@ -976,7 +997,7 @@ public function havingLike($field, string $match = '', string $side = 'both', ?b
976997 * Generates a NOT LIKE portion of the query.
977998 * Separates multiple calls with 'AND'.
978999 *
979- * @param mixed $field
1000+ * @param array|RawSql|string $field
9801001 *
9811002 * @return $this
9821003 */
@@ -989,7 +1010,7 @@ public function notHavingLike($field, string $match = '', string $side = 'both',
9891010 * Generates a %LIKE% portion of the query.
9901011 * Separates multiple calls with 'OR'.
9911012 *
992- * @param mixed $field
1013+ * @param array|RawSql|string $field
9931014 *
9941015 * @return $this
9951016 */
@@ -1002,7 +1023,7 @@ public function orHavingLike($field, string $match = '', string $side = 'both',
10021023 * Generates a NOT LIKE portion of the query.
10031024 * Separates multiple calls with 'OR'.
10041025 *
1005- * @param mixed $field
1026+ * @param array|RawSql|string $field
10061027 *
10071028 * @return $this
10081029 */
@@ -1021,20 +1042,50 @@ public function orNotHavingLike($field, string $match = '', string $side = 'both
10211042 * @used-by notHavingLike()
10221043 * @used-by orNotHavingLike()
10231044 *
1024- * @param mixed $field
1045+ * @param array|RawSql|string $field
10251046 *
10261047 * @return $this
10271048 */
10281049 protected function _like ($ field , string $ match = '' , string $ type = 'AND ' , string $ side = 'both ' , string $ not = '' , ?bool $ escape = null , bool $ insensitiveSearch = false , string $ clause = 'QBWhere ' )
10291050 {
1030- if (! is_array ($ field )) {
1031- $ field = [$ field => $ match ];
1032- }
1033-
10341051 $ escape = is_bool ($ escape ) ? $ escape : $ this ->db ->protectIdentifiers ;
10351052 $ side = strtolower ($ side );
10361053
1037- foreach ($ field as $ k => $ v ) {
1054+ if ($ field instanceof RawSql) {
1055+ $ k = (string ) $ field ;
1056+ $ v = $ match ;
1057+ $ insensitiveSearch = false ;
1058+
1059+ $ prefix = empty ($ this ->{$ clause }) ? $ this ->groupGetType ('' ) : $ this ->groupGetType ($ type );
1060+
1061+ if ($ side === 'none ' ) {
1062+ $ bind = $ this ->setBind ($ field ->getBindingKey (), $ v , $ escape );
1063+ } elseif ($ side === 'before ' ) {
1064+ $ bind = $ this ->setBind ($ field ->getBindingKey (), "% {$ v }" , $ escape );
1065+ } elseif ($ side === 'after ' ) {
1066+ $ bind = $ this ->setBind ($ field ->getBindingKey (), "{$ v }% " , $ escape );
1067+ } else {
1068+ $ bind = $ this ->setBind ($ field ->getBindingKey (), "% {$ v }% " , $ escape );
1069+ }
1070+
1071+ $ likeStatement = $ this ->_like_statement ($ prefix , $ k , $ not , $ bind , $ insensitiveSearch );
1072+
1073+ // some platforms require an escape sequence definition for LIKE wildcards
1074+ if ($ escape === true && $ this ->db ->likeEscapeStr !== '' ) {
1075+ $ likeStatement .= sprintf ($ this ->db ->likeEscapeStr , $ this ->db ->likeEscapeChar );
1076+ }
1077+
1078+ $ this ->{$ clause }[] = [
1079+ 'condition ' => $ field ->with ($ likeStatement ),
1080+ 'escape ' => $ escape ,
1081+ ];
1082+
1083+ return $ this ;
1084+ }
1085+
1086+ $ keyValue = ! is_array ($ field ) ? [$ field => $ match ] : $ field ;
1087+
1088+ foreach ($ keyValue as $ k => $ v ) {
10381089 if ($ insensitiveSearch === true ) {
10391090 $ v = strtolower ($ v );
10401091 }
@@ -1269,8 +1320,8 @@ public function groupBy($by, ?bool $escape = null)
12691320 /**
12701321 * Separates multiple calls with 'AND'.
12711322 *
1272- * @param array|string $key
1273- * @param mixed $value
1323+ * @param array|RawSql| string $key
1324+ * @param mixed $value
12741325 *
12751326 * @return $this
12761327 */
@@ -1282,8 +1333,8 @@ public function having($key, $value = null, ?bool $escape = null)
12821333 /**
12831334 * Separates multiple calls with 'OR'.
12841335 *
1285- * @param array|string $key
1286- * @param mixed $value
1336+ * @param array|RawSql| string $key
1337+ * @param mixed $value
12871338 *
12881339 * @return $this
12891340 */
@@ -2339,6 +2390,8 @@ protected function compileSelect($selectOverride = false): string
23392390
23402391 if (empty ($ this ->QBSelect )) {
23412392 $ sql .= '* ' ;
2393+ } elseif ($ this ->QBSelect [0 ] instanceof RawSql) {
2394+ $ sql .= (string ) $ this ->QBSelect [0 ];
23422395 } else {
23432396 // Cycle through the "select" portion of the query and prep each column name.
23442397 // The reason we protect identifiers here rather than in the select() function
@@ -2407,6 +2460,12 @@ protected function compileWhereHaving(string $qbKey): string
24072460 continue ;
24082461 }
24092462
2463+ if ($ qbkey ['condition ' ] instanceof RawSql) {
2464+ $ qbkey = $ qbkey ['condition ' ];
2465+
2466+ continue ;
2467+ }
2468+
24102469 if ($ qbkey ['escape ' ] === false ) {
24112470 $ qbkey = $ qbkey ['condition ' ];
24122471
0 commit comments