Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vsprintf(): Too few arguments #296

Closed
rajnishmishra20 opened this issue Oct 12, 2019 · 23 comments
Closed

vsprintf(): Too few arguments #296

rajnishmishra20 opened this issue Oct 12, 2019 · 23 comments
Assignees
Labels

Comments

@rajnishmishra20
Copy link

rajnishmishra20 commented Oct 12, 2019

Describe the bug
Exception occurs when using eagerLoadRelation on Model with Cachable trait.

Eloquent Query

$parents = Category::where('category_id', Category::encodeUuid($uuid))->with('word')->with('posts')->withCount('posts')->get();

Stack Trace
vsprintf(): Too few arguments

protected function getInAndNotInClauses(array $where) : string
{
    if (! in_array($where["type"], ["In", "NotIn", "InRaw"])) {
        return "";
    }

    $type = strtolower($where["type"]);
    $subquery = $this->getValuesFromWhere($where);
    $values = collect($this->query->bindings["where"][$this->currentBinding] ?? []);
    $this->currentBinding += count($where["values"]);
    $subquery = collect(**vsprintf**(str_replace("?", "%s", $subquery), $values->toArray()));
    $values = $this->recursiveImplode($subquery->toArray(), "_");

    return "-{$where["column"]}_{$type}{$values}";
}

Environment

  • PHP: [ 7.3.0]
  • OS: [ Ubuntu 18.04]
  • Laravel: [e.g. 5.8.]
  • Model Caching: [ 0.7] (*)

Model uses \Ramsey\Uuid\Uuid for primary keys

@mikebronner
Copy link
Owner

@rajnishmishra20 Thanks for reporting this. Could you provide the complete stack trace entry from /storage/logs/laravel.log? Thanks!

@mikebronner
Copy link
Owner

@rajnishmishra20 Thanks, that helps. I will try to get a fix out today or tomorrow.

@mikebronner
Copy link
Owner

@rajnishmishra20 Are you able to reproduce this in a model that doesn't use UUID?
Also, can you provide me the string value of Category::encodeUuid($uuid)? Thanks. I am currently unable to replicate the issue using the following query:

        $parents = (new Book)
            ->where('author_id', 1)
            ->with('stores')
            ->with('publisher')
            ->withCount('stores')
            ->get();

@rajnishmishra20
Copy link
Author

rajnishmishra20 commented Oct 18, 2019

Hi I am \Ramsey\Uuid\Uuid for primary keys

This is Category::decodeUuid($uuid) 8eae24c5cd3a484fb95259066fa9e83f

This is Category::encodeUuid($uuid) b"Ž®$ÅÍ:HO¹RY\x06o©è?"

Hope this helps.

@mikebronner
Copy link
Owner

@rajnishmishra20 Thanks, this helps. The problem is the question mark in the ID. I will see what I can do to work around this. Hopefully I will have an update ready sometime in the next few days.

@mikebronner
Copy link
Owner

@rajnishmishra20 This should now be fixed in release 0.7.3. Could you let me know how that works for you? Thanks!

@rajnishmishra20
Copy link
Author

Its fine now. Thanks!

@rajnishmishra20
Copy link
Author

rajnishmishra20 commented Oct 25, 2019

Hey Sorry to open this again but it did not work. I had MODEL_CACHE_ENABLED set to false

After enabling , same error occurs

My Query

Category::with('word')->with('contents')->with('category')->doesntHave('category')->with('packswithcontents')->simplePaginate($pages)

for a temporary access here is the url https://dev.coloursapp.com/api/content/v1/categories

    protected function getInAndNotInClauses(array $where) : string
    {
        if (! in_array($where["type"], ["In", "NotIn", "InRaw"])) {
            return "";
        }
 
        $type = strtolower($where["type"]);
        $subquery = $this->getValuesFromWhere($where);
        $values = collect($this->query->bindings["where"][$this->currentBinding] ?? []);
        $this->currentBinding += count($where["values"]);
        $subquery = preg_replace('/\?(?=(?:[^"]*"[^"]*")*[^"]*\Z)/m', "_??_", $subquery);
###       $subquery = collect(vsprintf(str_replace("_??_", "%s", $subquery), $values->toArray()));
        $values = $this->recursiveImplode($subquery->toArray(), "_");
 
        return "-{$where["column"]}_{$type}{$values}";
    }

@mikebronner
Copy link
Owner

Hi @rajnishmishra20, could you provide the stacktrace again, as well as the category UUIDs that cause this error? Thanks!

@mikebronner mikebronner reopened this Oct 25, 2019
@mikebronner
Copy link
Owner

Just saw you added the example link, thanks for that.
Inspecting the queries that are being run, the following looks odd to me:

select * from `categories` where `categories`.`id` in ('????????????????') and `categories`.`deleted_at` is null and `categories`.`deleted_at` is null

@rajnishmishra20
Copy link
Author

rajnishmishra20 commented Oct 27, 2019

Hi may be, I found the root of problem. when ever I try to egarload a relation with another elager loaded relation all having a binary id th problem occurs.

Ex if from Category::with('word')->with('contents')->with('category')->doesntHave('category')->with('packs')->simplePaginate($pages);

Suppose ->with('packs') contains another relation on model definition of relation the problem occurs
public function packs()
{
return $this->hasMany(Category::class, 'category_id')->with('contents');
}

if I remove ->with('contents') above it will work , else it will not.

https://dev.coloursapp.com/api/content/v1/categories
link is working as changes made above.

@mikebronner
Copy link
Owner

@rajnishmishra20 I need the values that are being passed in to work around the binary data.

@rajnishmishra20
Copy link
Author

rajnishmishra20 commented Oct 31, 2019

Some example categories

array:22 [▼
0 => b"Ž€E6Ó\x19Jý°\x1Ak%‚®éí"
1 => b"ÄÇEâ3ÎM¦ñ┌?╬³çÅC"
2 => b"Ž€E¯{ÔJ›…\x03¨)L/òº"
3 => b"Ž€Eç?ML%µ\x1EGUY\x128«"
4 => b"Ž€F\x03\½JÚšbå.ª\x124ö"
5 => b"Ž€F›Â…E\x03’ÇÄá]4Ÿ1"
6 => b"Ž€F»JœEf˜\x1FYÌZ»óJ"
7 => b"Ž€G›{CL%½¾\x07Â@Çû¤"
8 => b"""ÄÇHVJAÅÉïƒ ¶ÌÖj"""
9 => b"Ž€IS †I:ŽrÐ\x1Fç¤Û\x13"
10 => b"Ž€K¹ë\eIc™ˆor6ÄIK"
11 => b"Ž€LS¤‡Kð’ûcº_ï\x139"
12 => b"Ž€L¨¶ôFü§pvà1À?~"
13 => b"Ž€LîlâLö™Ï÷,&ÿ\x08±"
14 => b"ÄÇM>¨NK¶ñÃh\x04Ø├gA"
15 => b"ÄäMì┴×Gù½ôWÝ\x11ES²"
16 => b"Žñ\x02\x08\x17\x00NP†o«ã\tvžt"
17 => b"Žñ\x03\x05]ðH•†7¼o…Sþ\x05"
18 => b"Žñ\x03/¡~M¨—Ó1a\x7FN`)"
19 => b"Žñ\x03[N\x1DA˼ú½¥r\x10äá"
20 => b"Žñ\x1EzÃh@{’7Î4ÿ–Á-"
21 => b"Žñ )XmN;·RÒö\x03À3c"
]

array:1 [▼
0 => b"ÄÇEâ3ÎM¦ñ┌?╬³çÅC"
]

array:21 [▼
0 => b"Ž€E6Ó\x19Jý°\x1Ak%‚®éí"
2 => b"Ž€E¯{ÔJ›…\x03¨)L/òº"
3 => b"Ž€Eç?ML%µ\x1EGUY\x128«"
4 => b"Ž€F\x03\½JÚšbå.ª\x124ö"
5 => b"Ž€F›Â…E\x03’ÇÄá]4Ÿ1"
6 => b"Ž€F»JœEf˜\x1FYÌZ»óJ"
7 => b"Ž€G›{CL%½¾\x07Â@Çû¤"
8 => b"""ÄÇHVJAÅÉïƒ ¶ÌÖj"""
9 => b"Ž€IS †I:ŽrÐ\x1Fç¤Û\x13"
10 => b"Ž€K¹ë\eIc™ˆor6ÄIK"
11 => b"Ž€LS¤‡Kð’ûcº_ï\x139"
12 => b"Ž€L¨¶ôFü§pvà1À?~"
13 => b"Ž€LîlâLö™Ï÷,&ÿ\x08±"
14 => b"ÄÇM>¨NK¶ñÃh\x04Ø├gA"
15 => b"ÄäMì┴×Gù½ôWÝ\x11ES²"
16 => b"Žñ\x02\x08\x17\x00NP†o«ã\tvžt"
17 => b"Žñ\x03\x05]ðH•†7¼o…Sþ\x05"
18 => b"Žñ\x03/¡~M¨—Ó1a\x7FN`)"
19 => b"Žñ\x03[N\x1DA˼ú½¥r\x10äá"
20 => b"Žñ\x1EzÃh@{’7Î4ÿ–Á-"
21 => b"Žñ )XmN;·RÒö\x03À3c"
]

Category::whereIn('id', $parents)

passing last array in $parents makes the above exception

some binary ids have """

@padre
Copy link
Contributor

padre commented Nov 8, 2019

@mikebronner, this exception happens to me frequently :-(

My models uses \Ramsey\Uuid\Uuid too. An example:

vsprintf(): Too few arguments {"userId":15,"exception":"[object] (ErrorException(code: 0): vsprintf(): Too few arguments at /var/app/current/vendor/genealabs/laravel-model-caching/src/CacheKey.php:233) [stacktrace] #0 [internal function]: Illuminate\\Foundation\\Bootstrap\\HandleExceptions->handleError(2, 'vsprintf(): Too...', '/var/app/curren...', 233, Array) #1 /var/app/current/vendor/genealabs/laravel-model-caching/src/CacheKey.php(233): vsprintf('%s%<\\x96\\xD3DN\\xB7\\x9C\\xE5'\\xF0\\xAB\\xE1...', Array) #2 /var/app/current/vendor/genealabs/laravel-model-caching/src/CacheKey.php(197): GeneaLabs\\LaravelModelCaching\\CacheKey->getInAndNotInClauses(Array) #3 [internal function]: GeneaLabs\\LaravelModelCaching\\CacheKey->GeneaLabs\\LaravelModelCaching\\{closure}(NULL, Array) #4 /var/app/current/vendor/laravel/framework/src/Illuminate/Support/Collection.php(890): array_reduce(Array, Object(Closure), NULL) #5 /var/app/current/vendor/genealabs/laravel-model-caching/src/CacheKey.php(201): Illuminate\\Support\\Collection->reduce(Object(Closure)) #6 /var/app/current/vendor/genealabs/laravel-model-caching/src/CacheKey.php(40): GeneaLabs\\LaravelModelCaching\\CacheKey->getWhereClauses() #7 /var/app/current/vendor/genealabs/laravel-model-caching/src/Traits/Caching.php(161): GeneaLabs\\LaravelModelCaching\\CacheKey->make(Array, NULL, '-first') #8 /var/app/current/vendor/genealabs/laravel-model-caching/src/Traits/Buildable.php(75): GeneaLabs\\LaravelModelCaching\\CachedBuilder->makeCacheKey(Array, NULL, '-first') #9 /var/app/current/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(450): GeneaLabs\\LaravelModelCaching\\CachedBuilder->first(Array)

Thanks for the great library.

@padre
Copy link
Contributor

padre commented Nov 18, 2019

@mikebronner Sometimes the exception vsprintf(): Too few arguments and other times vsprintf(): Argument number must be greater than zero in CacheKey.php:233

It's to be used binary uuid

I made the following fix in and the problem has not recurred:

protected function getInAndNotInClauses(array $where) : string
    {
        if (! in_array($where["type"], ["In", "NotIn", "InRaw"])) {
            return "";
        }

        $type = strtolower($where["type"]);
        $subquery = $this->getValuesFromWhere($where);
        $values = collect($this->query->bindings["where"][$this->currentBinding] ?? []);
        $this->currentBinding += count($where["values"]);
        
        if(!is_numeric($subquery) && !is_numeric(str_replace("_","",$subquery))){
            try{
                $subquery = \Ramsey\Uuid\Uuid::fromBytes($subquery);
                $values = $this->recursiveImplode([$subquery], "_");
                return "-{$where["column"]}_{$type}{$values}";
            }
            catch (\Exception $e){
                
            } 
        }
        
        $subquery = preg_replace('/\?(?=(?:[^"]*"[^"]*")*[^"]*\Z)/m', "_??_", $subquery);
        $subquery = collect(vsprintf(str_replace("_??_", "%s", $subquery), $values->toArray()));
        $values = $this->recursiveImplode($subquery->toArray(), "_");
        return "-{$where["column"]}_{$type}{$values}";
        
    }

@mikebronner
Copy link
Owner

@padre the UUID package you linked to should not be used as the primary key. However, I have added the code you recommended, as it does not break any test. Unfortunately the tests for this are very impractical. I would definitely appreciate a PR from you, if you have the time. Thanks!

@mikebronner
Copy link
Owner

mikebronner commented Dec 22, 2019

Closing this for now. Please check release 0.7.4 and let me know how it works for you.

@edtsz
Copy link

edtsz commented May 29, 2020

Hello,
I'm getting trouble with vsprintf too and also using UUID as PK whatever the uuid was not the issue

Document::select()
    ->with('author')
    ->whereIn('id', function ($query) use ($args) {
        return $query->from('comments')
            ->select('document_id')
            ->distinct()
            ->where('user_id', auth()->user()->getAuthIdentifier()) // deleting this line and works nice
            ->where('folder_id', $args['folder_id'])
            ->whereNull([
                'replaced_id',
                'archived_at',
                'deleted_at'
            ]);
    })
    ->paginate($args['limit'], [], 'page', $args['page']);

Laravel: 5.8
Model Cache: 0.5.6 (PS.: I tried the most recent version and also didn't wokt)

Stacktrace:

ERROR: vsprintf(): Too few arguments at vendor/genealabs/laravel-model-caching/src/CacheKey.php:232
[stacktrace]
#0 [internal function]: Illuminate\\Foundation\\Bootstrap\\HandleExceptions->handleError(2, 'vsprintf(): Too...', '/home/edtsz/R...', 232, Array)
#1 vendor/genealabs/laravel-model-caching/src/CacheKey.php(232): vsprintf('select distinct...', Array)
#2 vendor/genealabs/laravel-model-caching/src/CacheKey.php(197): GeneaLabs\\LaravelModelCaching\\CacheKey->getInAndNotInClauses(Array)
#3 [internal function]: GeneaLabs\\LaravelModelCaching\\CacheKey->GeneaLabs\\LaravelModelCaching\\{closure}(NULL, Array)
#4 vendor/laravel/framework/src/Illuminate/Support/Collection.php(1512): array_reduce(Array, Object(Closure), NULL)
#5 vendor/genealabs/laravel-model-caching/src/CacheKey.php(201): Illuminate\\Support\\Collection->reduce(Object(Closure))
#6 vendor/genealabs/laravel-model-caching/src/CacheKey.php(40): GeneaLabs\\LaravelModelCaching\\CacheKey->getWhereClauses()
#7 vendor/genealabs/laravel-model-caching/src/Traits/Caching.php(161): GeneaLabs\\LaravelModelCaching\\CacheKey->make(Array, NULL, '-paginate_by_60...')
#8 vendor/genealabs/laravel-model-caching/src/Traits/Buildable.php(160): GeneaLabs\\LaravelModelCaching\\CachedBuilder->makeCacheKey(Array, NULL, '-paginate_by_60...')
#9 app/GraphQL/Queries/Document/DocumentsByFolderQuery.php(143): GeneaLabs\\LaravelModelCaching\\CachedBuilder->paginate(60, Array, 'page', 1)
"}

Digging into the code I realize that $values is receiving just one of the where() params at this line
So I decide to make a few changes:

// so I changed from                                vvvvvvvvvvvvvvvvvvvvvvv
// $values = collect($this->query->bindings["where"][$this->currentBinding] ?? []);
// to
   $values = collect(array_slice($this->query->bindings["where"], 1, substr_count($subquery, '?')) ?? []);

after that everything seems to be running well (yet)
ps.: slice starting from 1 because my query has 2 wheres and I don't know why there is a 0 in front off them.
the only thing I didn't like that much is the index name:

genealabs:laravel-model-caching:mysql:prod:documents:documents:appmodelsdocument_*-sandbox_=_0-id_in_select_distinct_`document_id`_from_`comments`_where_`user_id`_=_zzzzzzzzzzzzzzzzzzzzzzz_and_`folder_id`_=_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx_and_`replaced_id`_is_null_and_`archived_at`_is_null_and_`deleted_at`_is_null-documents.deleted_at_null-mysql:prod:comments-comments.children-comments.children.user-comments.children.user.emails-comments.action-comments.events-comments.user-comments.user.emails-comments.user.organization-comments.user.organization.user-comments.link_orderBy_created_at_desc-paginate_by_60_page_1

@edtsz
Copy link

edtsz commented May 29, 2020

Something weird happens here, my other environment $this->query->bindings["where"] is correct, with just 2 indexes (my where params).. and $this->currentBinding has 0 value.
in this case this works:

$values = collect($this->query->bindings["where"] ?? []);

@mikebronner
Copy link
Owner

@edtsz You indicate you are running Laravel 5.8. The most recent version is only compatible with Laravel 7.x. You mentioned you tried the latest version of the package, did you try it with Laravel 7?

@edtsz
Copy link

edtsz commented May 29, 2020

@mikebronner while testing I tried replacing CacheKey.php file by a new one. Everything works fine (except with more then one where). Laravel still 5.8

@mikebronner
Copy link
Owner

@edtsz Sounds good ... sorry, we don't support older versions of this package. You're welcome to fork this project and make any fixes you need on your own branch for your own purposes.

@doiprojectcom
Copy link

$subquery = collect(**vsprintf**(str_replace("?", "%s", $subquery), $values->toArray()));
replace to
$subquery = collect(**vsprintf**(str_replace("?", "%%s", $subquery), $values->toArray()));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants